List:Commits« Previous MessageNext Message »
From:marc.alff Date:July 20 2007 3:43am
Subject:bk commit into 5.1 tree (malff:1.2516) BUG#25422
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of marcsql. When marcsql does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-07-19 19:43:15-06:00, malff@weblab.(none) +31 -0
  WL#3984 (Revise locking of mysql.general_log and mysql.slow_log)
  Bug#25422 (Hang with log tables)
  Bug 29129 (Resetting general_log while the GLOBAL READ LOCK is set causes
             a deadlock)
  
  NOTE TO REVIEWER:
  There is still an opened issue with this patch, see mysql-tests/t/disabled.def
  The test rpl_optimize dead locks, but it's unclear if this is because:
  - a new bug was introduced by this patch
  - an existing unrelated bug was exposed by this patch
  To discuss during review, this point needs further investigation.
  
  ------
  
  Prior to this fix, the server would hang when performing concurrent
  ALTER TABLE or TRUNCATE TABLE statements against the LOG TABLES,
  which are mysql.general_log and mysql.slow_log.
  
  The root cause traces to the following code:
  in sql_base.cc, open_table()
    if (table->in_use != thd)
    {
      /* wait_for_condition will unlock LOCK_open for us */
      wait_for_condition(thd, &LOCK_open, &COND_refresh);
    }
  The problem with this code is that the current implementation of the
  LOGGER creates 'fake' THD objects, like
  - Log_to_csv_event_handler::general_log_thd
  - Log_to_csv_event_handler::slow_log_thd
  which are not associated to a real thread running in the server,
  so that waiting for these non-existing threads to release table locks
  cause the dead lock.
  
  In general, the design of Log_to_csv_event_handler does not fit into the
  general architecture of the server, so that the concept of general_log_thd
  and slow_log_thd has to be abandoned:
  - this implementation does not work with table locking
  - it will not work with commands like SHOW PROCESSLIST
  - having the log tables always opened does not integrate well with DDL
  operations / FLUSH TABLES / SET GLOBAL READ_ONLY
  
  With this patch, the fundamental design of the LOGGER has been changed to:
  - always open and close a log table when writing a log
  - remove totally the usage of fake THD objects
  - clarify how locking of log tables is implemented in general.
  
  Changing the locking design for log tables had some impact in several areas.
  The total change consist of:
  
  Part I: Technical changes
  
  1)
  
  bool TABLE_SHARE::system was too close to bool TABLE_SHARE::system_table,
  and has been renamed bool TABLE_SHARE::one_record_table
  
  2)
  
  bool TABLE_SHARE::system_table and bool TABLE_SHARE::log_table are related.
  Instead of multiplying various "is_X" "is_Y" boolean flags, the attribute
  TABLE_CATEGORY TABLE_SHARE::table_category has been introduced, that better
  describe the nature of the table.
  
  3)
  
  The enum TABLE_CATEGORY has been introduced, see the comments there.
  
  Special exceptions regarding FLUSH TABLES WITH READ LOCK or
  SET GLOBAL READ_ONLY=ON, in lock.cc, are now implemented with more clarity
  with the use of honor_global_locks().
  
  In general, helpers like honor_XYZ() are encouraged, as this breaks the
  correlation between
  - how a table behaves with regards to 1 property (global read lock, ...)
  - what the table is used for (user, system, ...)
  
  4)
  
  my_bool TABLE_SHARE::locked_by_logger has been removed, this was an artificial
  hack.
  
  5)
  
  The previous implementation confused:
  - 'system table' with ENGINE = MYISAM
  - 'log table' with ENGINE = CSV
  so that logic related to enforcing constraints for what the SQL layer
  considers 'system' or 'log' tables was not implemented in the SQL layer but
  in the storage engines.
  
  The methods:
  - handler::check_if_locking_is_allowed
  - handler::check_if_log_table_locking_is_allowed
  - ha_tina::check_if_locking_is_allowed
  - ha_myisam::check_if_locking_is_allowed
  have been removed, and the logic implemented in lock.cc instead.
  
  6)
  
  The fake threads, Log_to_csv_event_handler::general_log_thd and
  Log_to_csv_event_handler::slow_log_thd, are removed
  
  7)
  
  In general, a lot of code in log.h / log.cc dealing with opening / closing
  tables has been removed.
  
  8)
  
  Writing to the log tables is still a privileged operation.
  Before, it was enforced by testing that the 'current thread is the logger
  thread'. Now, it's enforced by the use of the internal flag
  OPTION_INTERNAL_PRIVILEGE
  
  9)
  
  TRUNCATE TABLE does not interfere with the logger implementation any more,
  all the code used to 'shutdown the logger, truncate, then restart the logger'
  is removed, and the operation is online.
  
  TRUNCATE TABLE uses OPTION_INTERNAL_PRIVILEGE, since it may need to use
  write locks.
  
  10)
  
  RENAME TABLE does not interfere with the logger implementation any more,
  regular table locking rules should apply even with log tables.
  
  11)
  
  Special rules for log tables in ALTER TABLES have been implemented in a
  dedicated helper/wrapper, for clarity.
  
  mysql_alter_table() uses OPTION_INTERNAL_PRIVILEGE, then invokes the
  ALTER TABLE implementation: mysql_alter_table_impl()
  
  This ensures that -- given the complexity of mysql_alter_table_impl() --
  every path of execution properly unset OPTION_INTERNAL_PRIVILEGE at the end.
  
  Note that the operation is online, as the logger is not locked.
  
  Part II: functional changes
  
  12)
  
  The previous implementation enforced that :
  - LOCK TABLE mysql.general_log WRITE
  - LOCK TABLE mysql.general_log READ
  was prohibited (even for SUPER), while
  - LOCK TABLE mysql.general_log READ LOCAL
  was allowed.
  
  The rational behind this was that WRITE and READ would freeze the server
  when running with SET GLOBAL GENERAL_LOG=ON, and should (rightfully) be
  prohibited.
  
  Allowing READ LOCAL was assuming that no dead locks can occur because of this
  lock, so that it's not harmful.
  
  However, with the following scenario:
  THD1: LOCK TABLE mysql.general_log READ LOCAL;
  THD2: TRUNCATE TABLE mysql.general_log;
  THD1: <any query, even "select 1 from dual> --> deadlock.
  
  The dead lock occurs because TRUNCATE uses a name lock and waits for *all*
  locks to disappear.
  THD1 dead locks while writing to the general_log, which can't get a write lock
  because of TRUNCATE.
  
  So, allowing even READ LOCAL on log tables can lead to a complete dead lock of
  the server, where 'complete' means :
  - new clients can't connect (stuck while printing in the general log)
  - new queries from existing clients can't execute (same)
  - the server does not respond to kill -15 (as seen during testing)
  
  The functional change introduced by this patch is to deny *any* form of
  locking what-so-ever on log tables, so that :
  LOCK TABLE mysql.general_log READ LOCAL is now denied.
  
  13)
  
  FLUSH LOGS does not flush the log tables any more.
  
  14)
  
  FLUSH TABLES does flush the log tables, it used to ignore them.
  
  Part III: more technical changes
  
  15)
  
  Implementing the restriction 12) above exposed a bug in mysqldump, which would
  ignore some tables in dump_all_tables_in_db(), but forget to ignore the same
  in dump_all_views_in_db().
  
  This has been fixed.
  
  16)
  
  mysqldump would also issue an empty "LOCK TABLE" command when all the tables
  to lock are to be ignored (numrows == 0), instead of not issuing the query.
  
  This has been fixed.
  
  17)
  
  Internal errors handlers could intercept errors but not warnings
  (see sql_error.cc), this has been fixed.
  
  It was found because writing to the general log or the slow log needs to
  filter out any error or warning, to avoid affecting the client performing
  the query with unrelated noise.
  
  18)
  
  Implementing a nested call to open tables, for the performance schema tables,
  exposed an existing bug in remove_table_from_cache(), which would perform:
    in_use->some_tables_deleted=1;
  against another thread, without any consideration about thread locking.
  This call inside remove_table_from_cache() was not required anyway,
  since calling mysql_lock_abort() takes care of aborting -- cleanly -- threads
  that might hold a lock on a table.
  This line (in_use->some_tables_deleted=1) has been removed.

  client/mysqldump.c@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +15 -4
    Don't lock tables in the ignore list.
    Don't issue empty LOCK TABLES queries.

  mysql-test/r/log_state.result@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +22 -0
    Adjust test results

  mysql-test/r/log_tables.result@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +98 -24
    Adjust test results

  mysql-test/r/ps.result@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +23 -31
    Adjust test results

  mysql-test/r/show_check.result@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +14 -17
    Adjust test results

  mysql-test/r/status.result@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +6 -6
    Adjust test results

  mysql-test/t/log_state.test@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +53 -0
    Added tests for Bug#29129

  mysql-test/t/log_tables.test@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +157 -63
    Can not lock a log table: adjusted the tests.
    Added tests for Bug#25422

  mysql-test/t/ps.test@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +7 -0
    Make the test output deterministic

  mysql-test/t/show_check.test@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +7 -0
    Make the test output deterministic

  sql/handler.cc@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +7 -28
    Moved logic for system / log tables in the SQL layer.

  sql/handler.h@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +1 -38
    Moved logic for system / log tables in the SQL layer.

  sql/lock.cc@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +94 -20
    Revised locking of log tables

  sql/log.cc@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +246 -420
    Major cleanup: changed how log tables are locked / written to

  sql/log.h@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +7 -75
    Major cleanup: changed how log tables are locked / written to.

  sql/mysql_priv.h@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +16 -1
    performance schema helpers

  sql/set_var.cc@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +5 -11
    log tables cleanup

  sql/share/errmsg.txt@stripped, 2007-07-19 19:43:11-06:00, malff@weblab.(none) +1 -1
    Changed the wording of ER_CANT_READ_LOCK_LOG_TABLE

  sql/sql_base.cc@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +104 -39
    log tables cleanup
    performance schema helpers

  sql/sql_delete.cc@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +28 -24
    log tables cleanup in TRUNCATE

  sql/sql_error.cc@stripped, 2007-07-19 19:43:10-06:00, malff@weblab.(none) +3 -0
    Internal handlers can also intercept warnings

  sql/sql_rename.cc@stripped, 2007-07-19 19:43:11-06:00, malff@weblab.(none) +0 -20
    log tables cleanup in RENAME

  sql/sql_select.cc@stripped, 2007-07-19 19:43:11-06:00, malff@weblab.(none) +1 -1
    TABLE_SHARE::system -> TABLE_SHARE::one_record_table

  sql/sql_show.cc@stripped, 2007-07-19 19:43:11-06:00, malff@weblab.(none) +0 -3
    Move INFORMATION_SCHEMA_NAME to table.cc

  sql/sql_table.cc@stripped, 2007-07-19 19:43:11-06:00, malff@weblab.(none) +77 -55
    log tables cleanup (admin operations, ALTER TABLE)

  sql/table.cc@stripped, 2007-07-19 19:43:11-06:00, malff@weblab.(none) +62 -20
    Implemented TABLE_CATEGORY.

  sql/table.h@stripped, 2007-07-19 19:43:11-06:00, malff@weblab.(none) +111 -14
    Implemented TABLE_CATEGORY.

  storage/csv/ha_tina.cc@stripped, 2007-07-19 19:43:11-06:00, malff@weblab.(none) +0 -12
    Moved logic for system / log tables in the SQL layer.

  storage/csv/ha_tina.h@stripped, 2007-07-19 19:43:11-06:00, malff@weblab.(none) +0 -5
    Moved logic for system / log tables in the SQL layer.

  storage/myisam/ha_myisam.cc@stripped, 2007-07-19 19:43:11-06:00, malff@weblab.(none) +1 -35
    Moved logic for system / log tables in the SQL layer.

  storage/myisam/ha_myisam.h@stripped, 2007-07-19 19:43:11-06:00, malff@weblab.(none) +0 -5
    Moved logic for system / log tables in the SQL layer.

diff -Nrup a/client/mysqldump.c b/client/mysqldump.c
--- a/client/mysqldump.c	2007-06-05 15:23:54 -06:00
+++ b/client/mysqldump.c	2007-07-19 19:43:10 -06:00
@@ -3372,11 +3372,12 @@ static int dump_all_tables_in_db(char *d
   {
     DYNAMIC_STRING query;
     init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024);
-    for (numrows= 0 ; (table= getTableName(1)) ; numrows++)
+    for (numrows= 0 ; (table= getTableName(1)) ; )
     {
       char *end= strmov(afterdot, table);
       if (include_table(hash_key,end - hash_key))
       {
+        numrows++;
         dynstr_append_checked(&query, quote_name(table, table_buff, 1));
         dynstr_append_checked(&query, " READ /*!32311 LOCAL */,");
       }
@@ -3450,6 +3451,11 @@ static my_bool dump_all_views_in_db(char
   char *table;
   uint numrows;
   char table_buff[NAME_LEN*2+3];
+  char hash_key[2*NAME_LEN+2];  /* "db.tablename" */
+  char *afterdot;
+
+  afterdot= strmov(hash_key, database);
+  *afterdot++= '.';
 
   if (init_dumping(database, init_dumping_views))
     return 1;
@@ -3459,10 +3465,15 @@ static my_bool dump_all_views_in_db(char
   {
     DYNAMIC_STRING query;
     init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024);
-    for (numrows= 0 ; (table= getTableName(1)); numrows++)
+    for (numrows= 0 ; (table= getTableName(1)); )
     {
-      dynstr_append_checked(&query, quote_name(table, table_buff, 1));
-      dynstr_append_checked(&query, " READ /*!32311 LOCAL */,");
+      char *end= strmov(afterdot, table);
+      if (include_table(hash_key,end - hash_key))
+      {
+        numrows++;
+        dynstr_append_checked(&query, quote_name(table, table_buff, 1));
+        dynstr_append_checked(&query, " READ /*!32311 LOCAL */,");
+      }
     }
     if (numrows && mysql_real_query(mysql, query.str, query.length-1))
       DB_error(mysql, "when using LOCK TABLES");
diff -Nrup a/mysql-test/r/log_state.result b/mysql-test/r/log_state.result
--- a/mysql-test/r/log_state.result	2007-02-20 13:00:04 -07:00
+++ b/mysql-test/r/log_state.result	2007-07-19 19:43:10 -06:00
@@ -153,3 +153,25 @@ select * from mysql.general_log;
 event_time	user_host	thread_id	server_id	command_type	argument
 TIMESTAMP	USER_HOST	#	1	Query	drop table t1
 TIMESTAMP	USER_HOST	#	1	Query	select * from mysql.general_log
+SET @old_general_log_state = @@global.general_log;
+set @old_slow_log_state = @@global.slow_query_log;
+SET GLOBAL general_log = ON;
+SET GLOBAL slow_query_log = ON;
+FLUSH TABLES WITH READ LOCK;
+SET GLOBAL general_log = OFF;
+SET GLOBAL slow_query_log = OFF;
+UNLOCK TABLES;
+FLUSH TABLES WITH READ LOCK;
+SET GLOBAL general_log = ON;
+SET GLOBAL slow_query_log = ON;
+UNLOCK TABLES;
+SET GLOBAL READ_ONLY = ON;
+SET GLOBAL general_log = OFF;
+SET GLOBAL slow_query_log = OFF;
+SET GLOBAL READ_ONLY = OFF;
+SET GLOBAL READ_ONLY = ON;
+SET GLOBAL general_log = ON;
+SET GLOBAL slow_query_log = ON;
+SET GLOBAL READ_ONLY = OFF;
+SET GLOBAL general_log = @old_general_log_state;
+SET GLOBAL slow_query_log = @old_slow_log_state;
diff -Nrup a/mysql-test/r/log_tables.result b/mysql-test/r/log_tables.result
--- a/mysql-test/r/log_tables.result	2007-06-13 17:34:41 -06:00
+++ b/mysql-test/r/log_tables.result	2007-07-19 19:43:10 -06:00
@@ -33,26 +33,33 @@ ERROR HY000: You can't write-lock a log 
 lock tables mysql.slow_log WRITE;
 ERROR HY000: You can't write-lock a log table. Only read access is possible
 lock tables mysql.general_log READ;
-ERROR HY000: You can't use usual read lock with log tables. Try READ LOCAL instead
+ERROR HY000: You can't use locks with log tables.
 lock tables mysql.slow_log READ;
-ERROR HY000: You can't use usual read lock with log tables. Try READ LOCAL instead
+ERROR HY000: You can't use locks with log tables.
 lock tables mysql.slow_log READ LOCAL, mysql.general_log READ LOCAL;
-unlock tables;
-lock tables mysql.general_log READ LOCAL;
+ERROR HY000: You can't use locks with log tables.
 flush logs;
-unlock tables;
-select "Mark that we woke up from flush logs in the test"
-       as "test passed";
-test passed
-Mark that we woke up from flush logs in the test
-lock tables mysql.general_log READ LOCAL;
-truncate mysql.general_log;
-unlock tables;
-select "Mark that we woke up from TRUNCATE in the test"
-       as "test passed";
-test passed
-Mark that we woke up from TRUNCATE in the test
-use test;
+flush tables;
+SET GLOBAL GENERAL_LOG=ON;
+SET GLOBAL SLOW_QUERY_LOG=ON;
+show open tables;
+Database	Table	In_use	Name_locked
+mysql	general_log	0	0
+flush logs;
+show open tables;
+Database	Table	In_use	Name_locked
+mysql	general_log	0	0
+flush tables;
+show open tables;
+Database	Table	In_use	Name_locked
+mysql	general_log	0	0
+SET GLOBAL GENERAL_LOG=OFF;
+SET GLOBAL SLOW_QUERY_LOG=OFF;
+flush tables;
+show open tables;
+Database	Table	In_use	Name_locked
+SET GLOBAL GENERAL_LOG=ON;
+SET GLOBAL SLOW_QUERY_LOG=ON;
 truncate table mysql.general_log;
 set names utf8;
 create table bug16905 (s char(15) character set utf8 default 'пусто');
@@ -71,7 +78,7 @@ sleep(2)
 0
 select * from mysql.slow_log;
 start_time	user_host	query_time	lock_time	rows_sent	rows_examined	db	last_insert_id	insert_id	server_id	sql_text
-TIMESTAMP	USER_HOST	QUERY_TIME	00:00:00	1	0	test	0	0	1	select sleep(2)
+TIMESTAMP	USER_HOST	QUERY_TIME	00:00:00	1	0	mysql	0	0	1	select sleep(2)
 alter table mysql.general_log engine=myisam;
 ERROR HY000: You cannot 'ALTER' a log table if logging is enabled
 alter table mysql.slow_log engine=myisam;
@@ -162,11 +169,9 @@ ERROR HY000: You can't write-lock a log 
 lock tables mysql.slow_log WRITE;
 ERROR HY000: You can't write-lock a log table. Only read access is possible
 lock tables mysql.general_log READ;
-ERROR HY000: You can't use usual read lock with log tables. Try READ LOCAL instead
+ERROR HY000: You can't use locks with log tables.
 lock tables mysql.slow_log READ;
-ERROR HY000: You can't use usual read lock with log tables. Try READ LOCAL instead
-lock tables mysql.slow_log READ LOCAL, mysql.general_log READ LOCAL;
-unlock tables;
+ERROR HY000: You can't use locks with log tables.
 set global general_log='OFF';
 set global slow_query_log='OFF';
 set @save_storage_engine= @@session.storage_engine;
@@ -217,6 +222,7 @@ flush tables with read lock;
 unlock tables;
 use mysql;
 lock tables general_log read local, help_category read local;
+ERROR HY000: You can't use locks with log tables.
 unlock tables;
 use mysql;
 RENAME TABLE general_log TO renamed_general_log;
@@ -258,9 +264,9 @@ RENAME TABLE general_log TO general_log2
 set global slow_query_log='OFF';
 RENAME TABLE slow_log TO slow_log2;
 set global general_log='ON';
-ERROR HY000: Cannot activate 'general' log
+ERROR 42S02: Table 'mysql.general_log' doesn't exist
 set global slow_query_log='ON';
-ERROR HY000: Cannot activate 'slow query' log
+ERROR 42S02: Table 'mysql.slow_log' doesn't exist
 RENAME TABLE general_log2 TO general_log;
 RENAME TABLE slow_log2 TO slow_log;
 set global general_log='ON';
@@ -355,3 +361,71 @@ SET SESSION long_query_time =@old_long_q
 FLUSH LOGS;
 ALTER TABLE mysql.slow_log DROP COLUMN seq;
 ALTER TABLE mysql.slow_log ENGINE = CSV;
+drop procedure if exists proc25422_truncate_slow;
+drop procedure if exists proc25422_truncate_general;
+drop procedure if exists proc25422_alter_slow;
+drop procedure if exists proc25422_alter_general;
+use test//
+create procedure proc25422_truncate_slow (loops int)
+begin
+declare v1 int default 0;
+while v1 < loops do
+truncate mysql.slow_log;
+set v1 = v1 + 1;
+end while;
+end//
+create procedure proc25422_truncate_general (loops int)
+begin
+declare v1 int default 0;
+while v1 < loops do
+truncate mysql.general_log;
+set v1 = v1 + 1;
+end while;
+end//
+create procedure proc25422_alter_slow (loops int)
+begin
+declare v1 int default 0;
+declare ER_BAD_LOG_STATEMENT condition for 1575;
+declare continue handler for ER_BAD_LOG_STATEMENT begin end;
+while v1 < loops do
+set @old_log_state = @@global.slow_query_log;
+set global slow_query_log = 'OFF';
+alter table mysql.slow_log engine = CSV;
+set global slow_query_log = @old_log_state;
+set v1 = v1 + 1;
+end while;
+end//
+create procedure proc25422_alter_general (loops int)
+begin
+declare v1 int default 0;
+declare ER_BAD_LOG_STATEMENT condition for 1575;
+declare continue handler for ER_BAD_LOG_STATEMENT begin end;
+while v1 < loops do
+set @old_log_state = @@global.general_log;
+set global general_log = 'OFF';
+alter table mysql.general_log engine = CSV;
+set global general_log = @old_log_state;
+set v1 = v1 + 1;
+end while;
+end//
+"Serial test (proc25422_truncate_slow)"
+call proc25422_truncate_slow(100);
+"Serial test (proc25422_truncate_general)"
+call proc25422_truncate_general(100);
+"Serial test (proc25422_alter_slow)"
+call proc25422_alter_slow(100);
+"Serial test (proc25422_alter_general)"
+call proc25422_alter_general(100);
+"Parallel test"
+call proc25422_truncate_slow(100);
+call proc25422_truncate_slow(100);
+call proc25422_truncate_general(100);
+call proc25422_truncate_general(100);
+call proc25422_alter_slow(100);
+call proc25422_alter_slow(100);
+call proc25422_alter_general(100);
+call proc25422_alter_general(100);
+drop procedure proc25422_truncate_slow;
+drop procedure proc25422_truncate_general;
+drop procedure proc25422_alter_slow;
+drop procedure proc25422_alter_general;
diff -Nrup a/mysql-test/r/ps.result b/mysql-test/r/ps.result
--- a/mysql-test/r/ps.result	2007-06-07 02:39:10 -06:00
+++ b/mysql-test/r/ps.result	2007-07-19 19:43:10 -06:00
@@ -1850,61 +1850,57 @@ create procedure proc_1() flush tables;
 flush tables;
 show open tables from mysql;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
 select Host, User from mysql.user limit 0;
 Host	User
 select Host, Db from mysql.host limit 0;
 Host	Db
 show open tables from mysql;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
+mysql	slow_log	0	0
 mysql	host	0	0
 mysql	user	0	0
 call proc_1();
 show open tables from mysql;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
 select Host, User from mysql.user limit 0;
 Host	User
 select Host, Db from mysql.host limit 0;
 Host	Db
 show open tables from mysql;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
+mysql	slow_log	0	0
 mysql	host	0	0
 mysql	user	0	0
 call proc_1();
 show open tables from mysql;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
 select Host, User from mysql.user limit 0;
 Host	User
 select Host, Db from mysql.host limit 0;
 Host	Db
 show open tables from mysql;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
+mysql	slow_log	0	0
 mysql	host	0	0
 mysql	user	0	0
 call proc_1();
 show open tables from mysql;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
 select Host, User from mysql.user limit 0;
 Host	User
 select Host, Db from mysql.host limit 0;
 Host	Db
 show open tables from mysql;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
+mysql	slow_log	0	0
 mysql	host	0	0
 mysql	user	0	0
 flush tables;
@@ -1922,54 +1918,50 @@ select Host, Db from mysql.host limit 0;
 Host	Db
 show open tables from mysql;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
-mysql	host	0	0
 mysql	user	0	0
+mysql	general_log	0	0
+mysql	host	0	0
 prepare abc from "flush tables";
 execute abc;
 show open tables from mysql;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
 select Host, User from mysql.user limit 0;
 Host	User
 select Host, Db from mysql.host limit 0;
 Host	Db
 show open tables from mysql;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
+mysql	slow_log	0	0
 mysql	host	0	0
 mysql	user	0	0
 execute abc;
 show open tables from mysql;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
 select Host, User from mysql.user limit 0;
 Host	User
 select Host, Db from mysql.host limit 0;
 Host	Db
 show open tables from mysql;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
+mysql	slow_log	0	0
 mysql	host	0	0
 mysql	user	0	0
 execute abc;
 show open tables from mysql;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
 select Host, User from mysql.user limit 0;
 Host	User
 select Host, Db from mysql.host limit 0;
 Host	Db
 show open tables from mysql;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
+mysql	slow_log	0	0
 mysql	host	0	0
 mysql	user	0	0
 flush tables;
diff -Nrup a/mysql-test/r/show_check.result b/mysql-test/r/show_check.result
--- a/mysql-test/r/show_check.result	2007-06-15 00:53:44 -06:00
+++ b/mysql-test/r/show_check.result	2007-07-19 19:43:10 -06:00
@@ -146,14 +146,13 @@ drop table t1;
 flush tables;
 show open tables;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
 create table t1(n int);
 insert into t1 values (1);
 show open tables;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
+mysql	slow_log	0	0
 test	t1	0	0
 drop table t1;
 create table t1 (a int not null, b VARCHAR(10), INDEX (b) ) AVG_ROW_LENGTH=10 CHECKSUM=1 COMMENT="test" ENGINE=MYISAM MIN_ROWS=10 MAX_ROWS=100 PACK_KEYS=1 DELAY_KEY_WRITE=1 ROW_FORMAT=fixed;
@@ -567,24 +566,23 @@ SELECT 1 FROM mysql.db, mysql.proc, mysq
 1
 SHOW OPEN TABLES;
 Database	Table	In_use	Name_locked
-mysql	proc	0	0
+mysql	db	0	0
 test	urkunde	0	0
 mysql	time_zone	0	0
-mysql	db	0	0
+mysql	general_log	0	0
 test	txt1	0	0
-mysql	slow_log	1	0
+mysql	proc	0	0
 test	tyt2	0	0
-mysql	general_log	1	0
 mysql	user	0	0
 mysql	time_zone_name	0	0
 SHOW OPEN TABLES FROM mysql;
 Database	Table	In_use	Name_locked
-mysql	proc	0	0
-mysql	time_zone	0	0
 mysql	db	0	0
-mysql	slow_log	1	0
-mysql	general_log	1	0
+mysql	time_zone	0	0
+mysql	general_log	0	0
+mysql	slow_log	0	0
 mysql	user	0	0
+mysql	proc	0	0
 mysql	time_zone_name	0	0
 SHOW OPEN TABLES FROM mysql LIKE 'u%';
 Database	Table	In_use	Name_locked
@@ -597,16 +595,15 @@ test	tyt2	0	0
 mysql	time_zone_name	0	0
 SHOW OPEN TABLES LIKE '%o%';
 Database	Table	In_use	Name_locked
-mysql	proc	0	0
 mysql	time_zone	0	0
-mysql	slow_log	1	0
-mysql	general_log	1	0
+mysql	general_log	0	0
+mysql	slow_log	0	0
+mysql	proc	0	0
 mysql	time_zone_name	0	0
 FLUSH TABLES;
 SHOW OPEN TABLES;
 Database	Table	In_use	Name_locked
-mysql	general_log	1	0
-mysql	slow_log	1	0
+mysql	general_log	0	0
 DROP TABLE txt1;
 DROP TABLE tyt2;
 DROP TABLE urkunde;
diff -Nrup a/mysql-test/r/status.result b/mysql-test/r/status.result
--- a/mysql-test/r/status.result	2007-05-15 01:45:48 -06:00
+++ b/mysql-test/r/status.result	2007-07-19 19:43:10 -06:00
@@ -1,11 +1,11 @@
 flush status;
 show status like 'Table_lock%';
 Variable_name	Value
-Table_locks_immediate	0
+Table_locks_immediate	1
 Table_locks_waited	0
 select * from information_schema.session_status where variable_name like 'Table_lock%';
 VARIABLE_NAME	VARIABLE_VALUE
-TABLE_LOCKS_IMMEDIATE	0
+TABLE_LOCKS_IMMEDIATE	2
 TABLE_LOCKS_WAITED	0
 SET SQL_LOG_BIN=0;
 drop table if exists t1;
@@ -18,11 +18,11 @@ update t1 set n = 3;
 unlock tables;
 show status like 'Table_lock%';
 Variable_name	Value
-Table_locks_immediate	3
+Table_locks_immediate	15
 Table_locks_waited	1
 select * from information_schema.session_status where variable_name like 'Table_lock%';
 VARIABLE_NAME	VARIABLE_VALUE
-TABLE_LOCKS_IMMEDIATE	3
+TABLE_LOCKS_IMMEDIATE	16
 TABLE_LOCKS_WAITED	1
 drop table t1;
 select 1;
@@ -97,7 +97,7 @@ Variable_name	Value
 Com_show_status	3
 show status like 'hand%write%';
 Variable_name	Value
-Handler_write	0
+Handler_write	5
 show status like '%tmp%';
 Variable_name	Value
 Created_tmp_disk_tables	0
@@ -105,7 +105,7 @@ Created_tmp_files	0
 Created_tmp_tables	0
 show status like 'hand%write%';
 Variable_name	Value
-Handler_write	0
+Handler_write	7
 show status like '%tmp%';
 Variable_name	Value
 Created_tmp_disk_tables	0
diff -Nrup a/mysql-test/t/log_state.test b/mysql-test/t/log_state.test
--- a/mysql-test/t/log_state.test	2007-03-23 06:39:15 -06:00
+++ b/mysql-test/t/log_state.test	2007-07-19 19:43:10 -06:00
@@ -126,6 +126,59 @@ drop table t1;
 --replace_column 1 TIMESTAMP 2 USER_HOST 3 #
 select * from mysql.general_log;
 
+#
+# Bug#29129 (Resetting general_log while the GLOBAL READ LOCK is set causes
+# a deadlock)
+
+# save state
+
+SET @old_general_log_state = @@global.general_log;
+set @old_slow_log_state = @@global.slow_query_log;
+
+# Test ON->OFF transition under a GLOBAL READ LOCK
+
+SET GLOBAL general_log = ON;
+SET GLOBAL slow_query_log = ON;
+
+FLUSH TABLES WITH READ LOCK;
+
+SET GLOBAL general_log = OFF;
+SET GLOBAL slow_query_log = OFF;
+
+UNLOCK TABLES;
+
+# Test OFF->ON transition under a GLOBAL READ LOCK
+
+FLUSH TABLES WITH READ LOCK;
+
+SET GLOBAL general_log = ON;
+SET GLOBAL slow_query_log = ON;
+
+UNLOCK TABLES;
+
+# Test ON->OFF transition under a GLOBAL READ_ONLY
+
+SET GLOBAL READ_ONLY = ON;
+
+SET GLOBAL general_log = OFF;
+SET GLOBAL slow_query_log = OFF;
+
+SET GLOBAL READ_ONLY = OFF;
+
+# Test OFF->ON transition under a GLOBAL READ_ONLY
+
+SET GLOBAL READ_ONLY = ON;
+
+SET GLOBAL general_log = ON;
+SET GLOBAL slow_query_log = ON;
+
+SET GLOBAL READ_ONLY = OFF;
+
+# Restore state
+
+SET GLOBAL general_log = @old_general_log_state;
+SET GLOBAL slow_query_log = @old_slow_log_state;
+
 --enable_ps_protocol
 
 #
diff -Nrup a/mysql-test/t/log_tables.test b/mysql-test/t/log_tables.test
--- a/mysql-test/t/log_tables.test	2007-06-13 17:34:41 -06:00
+++ b/mysql-test/t/log_tables.test	2007-07-19 19:43:10 -06:00
@@ -83,71 +83,44 @@ lock tables mysql.general_log READ;
 lock tables mysql.slow_log READ;
 
 #
-# This call should result in TL_READ lock on the log table. This is ok and
-# should pass.
+# This call should result in TL_READ lock on the log table.
+# This is not ok and should fail.
 #
 
+--error ER_CANT_READ_LOCK_LOG_TABLE
 lock tables mysql.slow_log READ LOCAL, mysql.general_log READ LOCAL;
 
-unlock tables;
-
 #
-# check that FLUSH LOGS waits for all readers of the log table to vanish
+# check that FLUSH LOGS does not flush the log tables
 #
 
-connect (con1,localhost,root,,);
-connect (con2,localhost,root,,);
-
-connection con1;
-
-lock tables mysql.general_log READ LOCAL;
-
-connection con2;
-
-# this should wait for log tables to unlock
-send flush logs;
-
-connection con1;
-
-unlock tables;
-
-# this connection should be alive by the time
-connection con2;
+flush logs;
+flush tables;
 
-reap;
+SET GLOBAL GENERAL_LOG=ON;
+SET GLOBAL SLOW_QUERY_LOG=ON;
 
-select "Mark that we woke up from flush logs in the test"
-       as "test passed";
+show open tables;
+flush logs;
+show open tables;
 
 #
-# perform the same check for TRUNCATE: it should also wait for readers
-# to disappear
+# check that FLUSH TABLES does flush the log tables
 #
 
-connection con1;
-
-lock tables mysql.general_log READ LOCAL;
-
-connection con2;
-
-# this should wait for log tables to unlock
-send truncate mysql.general_log;
-
-connection con1;
+flush tables;
+# Since the flush is logged, mysql.general_log will be in the cache
+show open tables;
 
-unlock tables;
-
-# this connection should be alive by the time
-connection con2;
-
-reap;
-
-select "Mark that we woke up from TRUNCATE in the test"
-       as "test passed";
+SET GLOBAL GENERAL_LOG=OFF;
+SET GLOBAL SLOW_QUERY_LOG=OFF;
 
-connection con1;
+flush tables;
+# Here the table cache is empty
+show open tables;
 
-use test;
+SET GLOBAL GENERAL_LOG=ON;
+SET GLOBAL SLOW_QUERY_LOG=ON;
 
 #
 # Bug #16905    Log tables: unicode statements are logged incorrectly
@@ -238,15 +211,6 @@ lock tables mysql.general_log READ;
 --error ER_CANT_READ_LOCK_LOG_TABLE
 lock tables mysql.slow_log READ;
 
-#
-# This call should result in TL_READ lock on the log table. This is ok and
-# should pass.
-#
-
-lock tables mysql.slow_log READ LOCAL, mysql.general_log READ LOCAL;
-
-unlock tables;
-
 # check that we can drop them
 set global general_log='OFF';
 set global slow_query_log='OFF';
@@ -314,6 +278,7 @@ use test;
 flush tables with read lock;
 unlock tables;
 use mysql;
+--error ER_CANT_READ_LOCK_LOG_TABLE
 lock tables general_log read local, help_category read local;
 unlock tables;
 
@@ -368,9 +333,9 @@ set global slow_query_log='OFF';
 RENAME TABLE slow_log TO slow_log2;
 
 # this should fail
---error ER_CANT_ACTIVATE_LOG
+--error ER_NO_SUCH_TABLE
 set global general_log='ON';
---error ER_CANT_ACTIVATE_LOG
+--error ER_NO_SUCH_TABLE
 set global slow_query_log='ON';
 
 RENAME TABLE general_log2 TO general_log;
@@ -470,8 +435,137 @@ FLUSH LOGS;
 ALTER TABLE mysql.slow_log DROP COLUMN seq;
 ALTER TABLE mysql.slow_log ENGINE = CSV;
 
-# kill all connections
-disconnect con1;
-disconnect con2;
+#
+# Bug#25422 (Hang with log tables)
+#
+
+--disable_warnings
+drop procedure if exists proc25422_truncate_slow;
+drop procedure if exists proc25422_truncate_general;
+drop procedure if exists proc25422_alter_slow;
+drop procedure if exists proc25422_alter_general;
+--enable_warnings
+
+delimiter //;
+
+use test//
+create procedure proc25422_truncate_slow (loops int)
+begin
+  declare v1 int default 0;
+  while v1 < loops do
+    truncate mysql.slow_log;
+    set v1 = v1 + 1;
+    end while;
+end//
+
+create procedure proc25422_truncate_general (loops int)
+begin
+  declare v1 int default 0;
+  while v1 < loops do
+    truncate mysql.general_log;
+    set v1 = v1 + 1;
+    end while;
+end//
+
+create procedure proc25422_alter_slow (loops int)
+begin
+  declare v1 int default 0;
+  declare ER_BAD_LOG_STATEMENT condition for 1575;
+  declare continue handler for ER_BAD_LOG_STATEMENT begin end;
+
+  while v1 < loops do
+    set @old_log_state = @@global.slow_query_log;
+    set global slow_query_log = 'OFF';
+    alter table mysql.slow_log engine = CSV;
+    set global slow_query_log = @old_log_state;
+    set v1 = v1 + 1;
+    end while;
+end//
+
+create procedure proc25422_alter_general (loops int)
+begin
+  declare v1 int default 0;
+  declare ER_BAD_LOG_STATEMENT condition for 1575;
+  declare continue handler for ER_BAD_LOG_STATEMENT begin end;
+
+  while v1 < loops do
+    set @old_log_state = @@global.general_log;
+    set global general_log = 'OFF';
+    alter table mysql.general_log engine = CSV;
+    set global general_log = @old_log_state;
+    set v1 = v1 + 1;
+    end while;
+end//
+
+delimiter ;//
+
+--echo "Serial test (proc25422_truncate_slow)"
+call proc25422_truncate_slow(100);
+--echo "Serial test (proc25422_truncate_general)"
+call proc25422_truncate_general(100);
+--echo "Serial test (proc25422_alter_slow)"
+call proc25422_alter_slow(100);
+--echo "Serial test (proc25422_alter_general)"
+call proc25422_alter_general(100);
+
+--echo "Parallel test"
+
+# ER_BAD_LOG_STATEMENT errors will occur,
+# since concurrent threads do SET GLOBAL general_log= ...
+# This is silenced by handlers and will not affect the test
+
+connect (addconroot1, localhost, root,,);
+connect (addconroot2, localhost, root,,);
+connect (addconroot3, localhost, root,,);
+connect (addconroot4, localhost, root,,);
+connect (addconroot5, localhost, root,,);
+connect (addconroot6, localhost, root,,);
+connect (addconroot7, localhost, root,,);
+connect (addconroot8, localhost, root,,);
+
+connection addconroot1;
+send call proc25422_truncate_slow(100);
+connection addconroot2;
+send call proc25422_truncate_slow(100);
+
+connection addconroot3;
+send call proc25422_truncate_general(100);
+connection addconroot4;
+send call proc25422_truncate_general(100);
+
+connection addconroot5;
+send call proc25422_alter_slow(100);
+connection addconroot6;
+send call proc25422_alter_slow(100);
+
+connection addconroot7;
+send call proc25422_alter_general(100);
+connection addconroot8;
+send call proc25422_alter_general(100);
+
+connection addconroot1;
+reap;
+connection addconroot2;
+reap;
+connection addconroot3;
+reap;
+connection addconroot4;
+reap;
+connection addconroot5;
+reap;
+connection addconroot6;
+reap;
+connection addconroot7;
+reap;
+connection addconroot8;
+reap;
+
+connection default;
+
+drop procedure proc25422_truncate_slow;
+drop procedure proc25422_truncate_general;
+drop procedure proc25422_alter_slow;
+drop procedure proc25422_alter_general;
+
 --enable_ps_protocol
 
diff -Nrup a/mysql-test/t/ps.test b/mysql-test/t/ps.test
--- a/mysql-test/t/ps.test	2007-06-14 17:33:40 -06:00
+++ b/mysql-test/t/ps.test	2007-07-19 19:43:10 -06:00
@@ -2018,10 +2018,17 @@ delimiter ;|
 select func_1(), func_1(), func_1() from dual;
 drop function func_1;
 drop procedure proc_1;
+
+# make the output deterministic:
+# the order used in SHOW OPEN TABLES
+# is too much implementation dependent
+--disable_ps_protocol
 flush tables;
 select Host, User from mysql.user limit 0;
 select Host, Db from mysql.host limit 0;
 show open tables from mysql;
+--enable_ps_protocol
+
 prepare abc from "flush tables";
 execute abc;
 show open tables from mysql;
diff -Nrup a/mysql-test/t/show_check.test b/mysql-test/t/show_check.test
--- a/mysql-test/t/show_check.test	2007-06-16 05:14:06 -06:00
+++ b/mysql-test/t/show_check.test	2007-07-19 19:43:10 -06:00
@@ -402,6 +402,11 @@ drop table if exists t1;
 CREATE TABLE txt1(a int);
 CREATE TABLE tyt2(a int);
 CREATE TABLE urkunde(a int);
+
+# make the output deterministic:
+# the order used in SHOW OPEN TABLES
+# is too much implementation dependent
+--disable_ps_protocol
 FLUSH TABLES;
 SELECT 1 FROM mysql.db, mysql.proc, mysql.user, mysql.time_zone, mysql.time_zone_name, txt1, tyt2, urkunde LIMIT 0;
 SHOW OPEN TABLES;
@@ -411,6 +416,8 @@ SHOW OPEN TABLES LIKE 't%';
 SHOW OPEN TABLES LIKE '%o%';
 FLUSH TABLES;
 SHOW OPEN TABLES;
+--enable_ps_protocol
+
 DROP TABLE txt1;
 DROP TABLE tyt2;
 DROP TABLE urkunde;
diff -Nrup a/sql/handler.cc b/sql/handler.cc
--- a/sql/handler.cc	2007-06-21 09:12:54 -06:00
+++ b/sql/handler.cc	2007-07-19 19:43:10 -06:00
@@ -1516,34 +1516,6 @@ THD *handler::ha_thd(void) const
 }
 
 
-bool handler::check_if_log_table_locking_is_allowed(uint sql_command,
-                                                    ulong type, TABLE *table)
-{
-  /*
-    Deny locking of the log tables, which is incompatible with
-    concurrent insert. The routine is not called if the table is
-    being locked from a logger THD (general_log_thd or slow_log_thd)
-    or from a privileged thread (see log.cc for details)
-  */
-  if (table->s->log_table &&
-      sql_command != SQLCOM_TRUNCATE &&
-      sql_command != SQLCOM_ALTER_TABLE &&
-      !(sql_command == SQLCOM_FLUSH &&
-        type & REFRESH_LOG) &&
-      (table->reginfo.lock_type >= TL_READ_NO_INSERT))
-  {
-    /*
-      The check  >= TL_READ_NO_INSERT denies all write locks
-      plus the only read lock (TL_READ_NO_INSERT itself)
-    */
-    table->reginfo.lock_type == TL_READ_NO_INSERT ?
-      my_error(ER_CANT_READ_LOCK_LOG_TABLE, MYF(0)) :
-        my_error(ER_CANT_WRITE_LOCK_LOG_TABLE, MYF(0));
-    return FALSE;
-  }
-  return TRUE;
-}
-
 /** @brief
   Open database-handler.
 
@@ -3680,6 +3652,13 @@ int handler::ha_write_row(uchar *buf)
     return error;
   return 0;
 }
+
+
+int handler::ha_write_row_no_binlog(uchar *buf)
+{
+  return write_row(buf);
+}
+
 
 int handler::ha_update_row(const uchar *old_data, uchar *new_data)
 {
diff -Nrup a/sql/handler.h b/sql/handler.h
--- a/sql/handler.h	2007-06-18 04:09:21 -06:00
+++ b/sql/handler.h	2007-07-19 19:43:10 -06:00
@@ -1027,44 +1027,6 @@ public:
   {
     cached_table_flags= table_flags();
   }
-  /*
-    Check whether a handler allows to lock the table.
-
-    SYNOPSIS
-      check_if_locking_is_allowed()
-        thd     Handler of the thread, trying to lock the table
-        table   Table handler to check
-        count   Total number of tables to be locked
-        current Index of the current table in the list of the tables
-                to be locked.
-        system_count Pointer to the counter of system tables seen thus
-                     far.
-        called_by_privileged_thread TRUE if called from a logger THD
-                                    (general_log_thd or slow_log_thd)
-                                    or by a privileged thread, which
-                                    has the right to lock log tables.
-
-    DESCRIPTION
-      Check whether a handler allows to lock the table. For instance,
-      MyISAM does not allow to lock mysql.proc along with other tables.
-      This limitation stems from the fact that MyISAM does not support
-      row-level locking and we have to add this limitation to avoid
-      deadlocks.
-
-    RETURN
-      TRUE      Locking is allowed
-      FALSE     Locking is not allowed. The error was thrown.
-  */
-  virtual bool check_if_locking_is_allowed(uint sql_command,
-                                           ulong type, TABLE *table,
-                                           uint count, uint current,
-                                           uint *system_count,
-                                           bool called_by_privileged_thread)
-  {
-    return TRUE;
-  }
-  bool check_if_log_table_locking_is_allowed(uint sql_command,
-                                             ulong type, TABLE *table);
   int ha_open(TABLE *table, const char *name, int mode, int test_if_locked);
   void adjust_next_insert_id_after_explicit_value(ulonglong nr);
   int update_auto_increment();
@@ -1185,6 +1147,7 @@ public:
    */
   int ha_external_lock(THD *thd, int lock_type);
   int ha_write_row(uchar * buf);
+  int ha_write_row_no_binlog(uchar * buf);
   int ha_update_row(const uchar * old_data, uchar * new_data);
   int ha_delete_row(const uchar * buf);
 
diff -Nrup a/sql/lock.cc b/sql/lock.cc
--- a/sql/lock.cc	2007-06-18 14:13:18 -06:00
+++ b/sql/lock.cc	2007-07-19 19:43:10 -06:00
@@ -117,10 +117,84 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, 
   MYSQL_LOCK *sql_lock;
   TABLE *write_lock_used;
   int rc;
+  uint i;
+  bool must_honor_global_lock;
+  uint system_count;
+
   DBUG_ENTER("mysql_lock_tables");
 
   *need_reopen= FALSE;
 
+  must_honor_global_lock= false;
+  system_count= 0;
+  for (i=0 ; i<count; i++)
+  {
+    TABLE *t= tables[i];
+
+    /* Protect against 'fake' partially initialized TABLE_SHARE */
+    DBUG_ASSERT(t->s->table_category != TABLE_UNKNOWN_CATEGORY);
+
+    /*
+      Table I/O to performance schema tables is performed
+      only internally by the server implementation.
+      When a user is requesting a lock, the following
+      constraints are enforced:
+    */
+    if (t->s->require_write_privileges() &&
+        !(thd->options & OPTION_INTERNAL_PRIVILEGE))
+    {
+      /*
+        A user should not be able to prevent writes,
+        since this would be a DOS attack.
+      */
+      if (t->reginfo.lock_type == TL_READ_NO_INSERT)
+      {
+        my_error(ER_CANT_READ_LOCK_LOG_TABLE, MYF(0));
+        DBUG_RETURN(0);
+      }
+      /*
+        A user should not be able to insert arbitrary
+        data into log tables.
+      */
+      if (t->reginfo.lock_type >= TL_READ_NO_INSERT)
+      {
+        my_error(ER_CANT_WRITE_LOCK_LOG_TABLE, MYF(0));
+        DBUG_RETURN(0);
+      }
+      /*
+        A user should not be able to hold a lock of any
+        kind in the session, this would be a DOS attack.
+      */
+      if (thd->lex->sql_command == SQLCOM_LOCK_TABLES)
+      {
+        my_error(ER_CANT_READ_LOCK_LOG_TABLE, MYF(0));
+        DBUG_RETURN(0);
+      }
+    }
+
+    if ((t->s->table_category == TABLE_CATEGORY_SYSTEM) &&
+        (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE))
+    {
+      system_count++;
+    }
+
+    if (t->s->honor_global_locks())
+    {
+      must_honor_global_lock= true;
+    }
+  }
+
+  /*
+    Locking of system tables is restricted:
+    locking a mix of system and non-system tables in the same lock
+    is prohibited, to prevent contention.
+  */
+  if ((system_count > 0) && (system_count < count))
+  {
+    my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0));
+    DBUG_RETURN(0);
+  }
+
   for (;;)
   {
     if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS,
@@ -128,7 +202,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, 
       break;
 
     if (global_read_lock && write_lock_used &&
-        ! (flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK))
+        ! (flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK) &&
+        must_honor_global_lock)
     {
       /*
 	Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
@@ -151,11 +226,11 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, 
       }
     }
 
-    if (!(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY) &&
-        write_lock_used &&
+    if (write_lock_used &&
         opt_readonly &&
         !(thd->security_ctx->master_access & SUPER_ACL) &&
-        !thd->slave_thread)
+        !thd->slave_thread &&
+        must_honor_global_lock)
     {
       /*
 	Someone has issued SET GLOBAL READ_ONLY=1 and we want a write lock.
@@ -205,7 +280,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, 
         preserved.
       */
       reset_lock_data(sql_lock);
-      thd->some_tables_deleted=1;		// Try again
+      thd->some_tables_deleted= 1;              // Try again
       sql_lock->lock_count= 0;                  // Locks are already freed
     }
     else if (!thd->some_tables_deleted || (flags & MYSQL_LOCK_IGNORE_FLUSH))
@@ -216,7 +291,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, 
     else if (!thd->open_tables)
     {
       // Only using temporary tables, no need to unlock
-      thd->some_tables_deleted=0;
+      thd->some_tables_deleted= 0;
       thd->locked=0;
       break;
     }
@@ -439,7 +514,8 @@ void mysql_lock_downgrade_write(THD *thd
 {
   MYSQL_LOCK *locked;
   TABLE *write_lock_used;
-  if ((locked = get_lock_data(thd,&table,1,1,&write_lock_used)))
+  if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
+                             &write_lock_used)))
   {
     for (uint i=0; i < locked->lock_count; i++)
       thr_downgrade_write_lock(locked->locks[i], new_lock_type);
@@ -698,25 +774,23 @@ static MYSQL_LOCK *get_lock_data(THD *th
   TABLE **to, **table_buf;
   DBUG_ENTER("get_lock_data");
 
+  DBUG_ASSERT((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS));
+
   DBUG_PRINT("info", ("count %d", count));
   *write_lock_used=0;
-  uint system_count= 0;
-  for (i=tables=lock_count=0 ; i < count ; i++)
+
+  tables= 0;
+  lock_count= 0;
+
+  for (i=0 ; i < count ; i++)
   {
-    if (table_ptr[i]->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE)
+    TABLE *t= table_ptr[i];
+
+    if (t->s->tmp_table != NON_TRANSACTIONAL_TMP_TABLE)
     {
-      tables+=table_ptr[i]->file->lock_count();
+      tables+= t->file->lock_count();
       lock_count++;
     }
-    /*
-      Check if we can lock the table. For some tables we cannot do that
-      beacause of handler-specific locking issues.
-    */
-    if (!table_ptr[i]-> file->
-          check_if_locking_is_allowed(thd->lex->sql_command, thd->lex->type,
-                                      table_ptr[i], count, i, &system_count,
-                                      logger.is_privileged_thread(thd)))
-      DBUG_RETURN(0);
   }
 
   /*
diff -Nrup a/sql/log.cc b/sql/log.cc
--- a/sql/log.cc	2007-06-15 11:36:14 -06:00
+++ b/sql/log.cc	2007-07-19 19:43:10 -06:00
@@ -57,6 +57,27 @@ static int binlog_commit(handlerton *hto
 static int binlog_rollback(handlerton *hton, THD *thd, bool all);
 static int binlog_prepare(handlerton *hton, THD *thd, bool all);
 
+class Silence_log_table_errors : public Internal_error_handler
+{
+public:
+  Silence_log_table_errors()
+  {}
+
+  virtual ~Silence_log_table_errors() {}
+
+  virtual bool handle_error(uint sql_errno,
+                            MYSQL_ERROR::enum_warning_level level,
+                            THD *thd);
+};
+
+bool
+Silence_log_table_errors::handle_error(uint /* sql_errno */,
+                                       MYSQL_ERROR::enum_warning_level /* level */,
+                                       THD * /* thd */)
+{
+  return true;
+}
+
 sql_print_message_func sql_print_message_handlers[3] =
 {
   sql_print_information,
@@ -188,6 +209,20 @@ public:
 handlerton *binlog_hton;
 
 
+bool LOGGER::is_log_table_enabled(uint log_table_type)
+{
+  switch (log_table_type) {
+  case QUERY_LOG_SLOW:
+    return (table_log_handler != NULL) && opt_slow_log;
+  case QUERY_LOG_GENERAL:
+    return (table_log_handler != NULL) && opt_log ;
+  default:
+    DBUG_ASSERT(0);
+    return FALSE;                             /* make compiler happy */
+  }
+}
+
+
 /* Check if a given table is opened log table */
 int check_if_log_table(uint db_len, const char *db, uint table_name_len,
                        const char *table_name, uint check_if_opened)
@@ -200,211 +235,38 @@ int check_if_log_table(uint db_len, cons
     if (table_name_len == 11 && !(lower_case_table_names ?
                                   my_strcasecmp(system_charset_info,
                                                 table_name, "general_log") :
-                                  strcmp(table_name, "general_log")) &&
-        (!check_if_opened || logger.is_log_table_enabled(QUERY_LOG_GENERAL)))
-      return QUERY_LOG_GENERAL;
-    else
-      if (table_name_len == 8 && !(lower_case_table_names ?
-        my_strcasecmp(system_charset_info, table_name, "slow_log") :
-        strcmp(table_name, "slow_log")) &&
-          (!check_if_opened ||logger.is_log_table_enabled(QUERY_LOG_SLOW)))
+                                  strcmp(table_name, "general_log")))
+    {
+      if (!check_if_opened || logger.is_log_table_enabled(QUERY_LOG_GENERAL))
+        return QUERY_LOG_GENERAL;
+      return 0;
+    }
+
+    if (table_name_len == 8 && !(lower_case_table_names ?
+      my_strcasecmp(system_charset_info, table_name, "slow_log") :
+      strcmp(table_name, "slow_log")))
+    {
+      if (!check_if_opened || logger.is_log_table_enabled(QUERY_LOG_SLOW))
         return QUERY_LOG_SLOW;
+      return 0;
+    }
   }
   return 0;
 }
 
 
-/*
-  Open log table of a given type (general or slow log)
-
-  SYNOPSIS
-    open_log_table()
-
-    log_table_type   type of the log table to open: QUERY_LOG_GENERAL
-                     or QUERY_LOG_SLOW
-
-  DESCRIPTION
-
-    The function opens a log table and marks it as such. Log tables are open
-    during the whole time, while server is running. Except for the moments
-    when they have to be reopened: during FLUSH LOGS and TRUNCATE. This
-    function is invoked directly only once during startup. All subsequent
-    calls happen through reopen_log_table(), which performs additional check.
-
-  RETURN
-    FALSE - OK
-    TRUE - error occured
-*/
-
-bool Log_to_csv_event_handler::open_log_table(uint log_table_type)
-{
-  THD *log_thd, *curr= current_thd;
-  TABLE_LIST *table;
-  bool error= FALSE;
-  DBUG_ENTER("open_log_table");
-
-  switch (log_table_type) {
-  case QUERY_LOG_GENERAL:
-    log_thd= general_log_thd;
-    table= &general_log;
-    /* clean up table before reuse/initial usage */
-    bzero((char*) table, sizeof(TABLE_LIST));
-    table->alias= table->table_name= (char*) "general_log";
-    table->table_name_length= 11;
-    break;
-  case QUERY_LOG_SLOW:
-    log_thd= slow_log_thd;
-    table= &slow_log;
-    bzero((char*) table, sizeof(TABLE_LIST));
-    table->alias= table->table_name= (char*) "slow_log";
-    table->table_name_length= 8;
-    break;
-  default:
-    assert(0);                                  // Impossible
-  }
-
-  /*
-    This way we check that appropriate log thd was created ok during
-    initialization. We cannot check "is_log_tables_initialized" var, as
-    the very initialization is not finished until this function is
-    completed in the very first time.
-  */
-  if (!log_thd)
-  {
-    DBUG_PRINT("error",("Cannot initialize log tables"));
-    DBUG_RETURN(TRUE);
-  }
-
-  /*
-    Set THD's thread_stack. This is needed to perform stack overrun
-    check, which is done by some routines (e.g. open_table()).
-    In the case we are called by thread, which already has this parameter
-    set, we use this value. Otherwise we do a wild guess. This won't help
-    to correctly track the stack overrun in these exceptional cases (which
-    could probably happen only during startup and shutdown) but at least
-    lets us to pass asserts.
-    The problem stems from the fact that logger THDs are not real threads.
-  */
-  if (curr)
-    log_thd->thread_stack= curr->thread_stack;
-  else
-    log_thd->thread_stack= (char*) &log_thd;
-
-  log_thd->store_globals();
-
-  table->lock_type= TL_WRITE_CONCURRENT_INSERT;
-  table->db= log_thd->db;
-  table->db_length= log_thd->db_length;
-
-  lex_start(log_thd);
-  log_thd->clear_error();
-  if (simple_open_n_lock_tables(log_thd, table) ||
-      table->table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE) ||
-      table->table->file->ha_rnd_init(0))
-    error= TRUE;
-  else
-  {
-    table->table->use_all_columns();
-    table->table->locked_by_logger= TRUE;
-    table->table->no_replicate= TRUE;
-
-    /* Honor next number columns if present */
-    table->table->next_number_field= table->table->found_next_number_field;
-  }
-  /* restore thread settings */
-  if (curr)
-    curr->store_globals();
-  else
-  {
-    my_pthread_setspecific_ptr(THR_THD,  0);
-    my_pthread_setspecific_ptr(THR_MALLOC, 0);
-  }
-
-  /*
-    After a log table was opened, we should clear privileged thread
-    flag (which allows locking of a log table by a special thread, usually
-    the one who closed log tables temporarily).
-  */
-  privileged_thread= 0;
-  DBUG_RETURN(error);
-}
-
-
 Log_to_csv_event_handler::Log_to_csv_event_handler()
 {
-  /* init artificial THD's */
-  general_log_thd= new THD;
-  /* logger thread always works with mysql database */
-  general_log_thd->db= my_strdup("mysql", MYF(0));
-  general_log_thd->db_length= 5;
-  general_log.table= 0;
-
-  slow_log_thd= new THD;
-  /* logger thread always works with mysql database */
-  slow_log_thd->db= my_strdup("mysql", MYF(0));;
-  slow_log_thd->db_length= 5;
-  slow_log.table= 0;
-  /* no privileged thread exists at the moment */
-  privileged_thread= 0;
 }
 
 
 Log_to_csv_event_handler::~Log_to_csv_event_handler()
 {
-  /* now cleanup the tables */
-  if (general_log_thd)
-  {
-    delete general_log_thd;
-    general_log_thd= NULL;
-  }
-
-  if (slow_log_thd)
-  {
-    delete slow_log_thd;
-    slow_log_thd= NULL;
-  }
-}
-
-
-/*
-  Reopen log table of a given type
-
-  SYNOPSIS
-    reopen_log_table()
-
-    log_table_type   type of the log table to open: QUERY_LOG_GENERAL
-                     or QUERY_LOG_SLOW
-
-  DESCRIPTION
-
-    The function is a wrapper around open_log_table(). It is used during
-    FLUSH LOGS and TRUNCATE of the log tables (i.e. when we need to close
-    and reopen them). The difference is in the check of the
-    logger.is_log_tables_initialized var, which can't be done in
-    open_log_table(), as it makes no sense during startup.
-
-    NOTE: this code assumes that we have logger mutex locked
-
-  RETURN
-    FALSE - ok
-    TRUE - open_log_table() returned an error
-*/
-
-bool Log_to_csv_event_handler::reopen_log_table(uint log_table_type)
-{
-  /* don't open the log table, if it wasn't enabled during startup */
-  if (!logger.is_log_tables_initialized)
-    return FALSE;
-  return open_log_table(log_table_type);
 }
 
 
 void Log_to_csv_event_handler::cleanup()
 {
-  if (opt_log)
-    close_log_table(QUERY_LOG_GENERAL, FALSE);
-  if (opt_slow_log)
-    close_log_table(QUERY_LOG_SLOW, FALSE);
   logger.is_log_tables_initialized= FALSE;
 }
 
@@ -436,49 +298,88 @@ void Log_to_csv_event_handler::cleanup()
 */
 
 bool Log_to_csv_event_handler::
-  log_general(time_t event_time, const char *user_host,
+  log_general(THD *thd, time_t event_time, const char *user_host,
               uint user_host_len, int thread_id,
               const char *command_type, uint command_type_len,
               const char *sql_text, uint sql_text_len,
               CHARSET_INFO *client_cs)
 {
-  TABLE *table= general_log.table;
+  TABLE_LIST table_list;
+  TABLE *table;
+  bool result= true;
+  bool need_close= false;
+  bool need_pop= false;
+  bool need_rnd_end= false;
   uint field_index;
+  Silence_log_table_errors error_handler;
+  Open_tables_state open_tables_backup;
+  Field_timestamp *field0;
+  ulonglong save_thd_options;
+  bool save_query_start_used;
+  time_t save_start_time;
+  time_t save_time_after_lock;
+  time_t save_user_time;
+  bool save_time_zone_used;
+
+  save_thd_options= thd->options;
+  thd->options&= ~OPTION_BIN_LOG;
+
+  save_query_start_used= thd->query_start_used;
+  save_start_time= thd->start_time;
+  save_time_after_lock= thd->time_after_lock;
+  save_user_time= thd->user_time;
+  save_time_zone_used= thd->time_zone_used;
+
+  bzero(& table_list, sizeof(TABLE_LIST));
+  table_list.alias= table_list.table_name= GENERAL_LOG_NAME.str;
+  table_list.table_name_length= GENERAL_LOG_NAME.length;
+
+  table_list.lock_type= TL_WRITE_CONCURRENT_INSERT;
+
+  table_list.db= MYSQL_SCHEMA_NAME.str;
+  table_list.db_length= MYSQL_SCHEMA_NAME.length;
+
+  table= open_performance_schema_table(thd, & table_list,
+                                       & open_tables_backup);
+  need_close= true;
+
+  if (!table ||
+      table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE) ||
+      table->file->ha_rnd_init(0))
+    goto err;
+
+  need_rnd_end= true;
+
+  /* Honor next number columns if present */
+  table->next_number_field= table->found_next_number_field;
 
   /*
     "INSERT INTO general_log" can generate warning sometimes.
-    Let's reset warnings from previous queries,
-    otherwise warning list can grow too much,
-    so thd->query gets spoiled as some point in time,
-    and mysql_parse() receives a broken query.
     QQ: this problem needs to be studied in more details.
-    Probably it's better to suppress warnings in logging INSERTs at all.
-    Comment this line and run "cast.test" to see what's happening:
+    Comment this 2 lines and run "cast.test" to see what's happening:
   */
-  mysql_reset_errors(table->in_use, 1);
-
-  /* below should never happen */
-  if (unlikely(!logger.is_log_tables_initialized))
-    return FALSE;
+  thd->push_internal_handler(& error_handler);
+  need_pop= true;
 
   /*
     NOTE: we do not call restore_record() here, as all fields are
     filled by the Logger (=> no need to load default ones).
   */
 
-  /* Set current time. Required for CURRENT_TIMESTAMP to work */
-  general_log_thd->start_time= event_time;
-
   /*
     We do not set a value for table->field[0], as it will use
     default value (which is CURRENT_TIMESTAMP).
   */
 
   /* check that all columns exist */
-  if (!table->field[1] || !table->field[2] || !table->field[3] ||
-      !table->field[4] || !table->field[5])
+  if (table->s->fields < 6)
     goto err;
 
+  DBUG_ASSERT(table->field[0]->type() == MYSQL_TYPE_TIMESTAMP);
+
+  field0= (Field_timestamp*) (table->field[0]);
+  field0->set_time();
+
   /* do a write */
   if (table->field[1]->store(user_host, user_host_len, client_cs) ||
       table->field[2]->store((longlong) thread_id, TRUE) ||
@@ -500,16 +401,32 @@ bool Log_to_csv_event_handler::
     table->field[field_index]->set_default();
   }
 
-  /* log table entries are not replicated at the moment */
-  tmp_disable_binlog(current_thd);
-
-  table->file->ha_write_row(table->record[0]);
+  table->file->ha_write_row_no_binlog(table->record[0]);
+  table->file->ha_rnd_end();
+  table->file->ha_release_auto_increment();
+  need_rnd_end= false;
 
-  reenable_binlog(current_thd);
+  result= false;
 
-  return FALSE;
 err:
-  return TRUE;
+  if (need_rnd_end)
+  {
+    table->file->ha_rnd_end();
+    table->file->ha_release_auto_increment();
+  }
+  if (need_pop)
+    thd->pop_internal_handler();
+  if (need_close)
+    close_performance_schema_table(thd, & open_tables_backup);
+
+  thd->options= save_thd_options;
+
+  thd->query_start_used= save_query_start_used;
+  thd->start_time= save_start_time;
+  thd->time_after_lock= save_time_after_lock;
+  thd->user_time= save_user_time;
+  thd->time_zone_used= save_time_zone_used;
+  return result;
 }
 
 
@@ -548,34 +465,61 @@ bool Log_to_csv_event_handler::
            longlong query_time, longlong lock_time, bool is_command,
            const char *sql_text, uint sql_text_len)
 {
-  /* table variables */
-  TABLE *table= slow_log.table;
+  TABLE_LIST table_list;
+  TABLE *table;
+  bool result= true;
+  bool need_close= false;
+  bool need_rnd_end= false;
+  Open_tables_state open_tables_backup;
+  bool save_query_start_used;
+  time_t save_start_time;
+  time_t save_time_after_lock;
+  time_t save_user_time;
+  bool save_time_zone_used;
   CHARSET_INFO *client_cs= thd->variables.character_set_client;
 
-  DBUG_ENTER("log_slow");
+  DBUG_ENTER("Log_to_csv_event_handler::log_slow");
 
-  /* below should never happen */
-  if (unlikely(!logger.is_log_tables_initialized))
-    return FALSE;
+  bzero(& table_list, sizeof(TABLE_LIST));
+  table_list.alias= table_list.table_name= SLOW_LOG_NAME.str;
+  table_list.table_name_length= SLOW_LOG_NAME.length;
+
+  table_list.lock_type= TL_WRITE_CONCURRENT_INSERT;
+
+  table_list.db= MYSQL_SCHEMA_NAME.str;
+  table_list.db_length= MYSQL_SCHEMA_NAME.length;
+
+  save_query_start_used= thd->query_start_used;
+  save_start_time= thd->start_time;
+  save_time_after_lock= thd->time_after_lock;
+  save_user_time= thd->user_time;
+  save_time_zone_used= thd->time_zone_used;
+
+  table= open_performance_schema_table(thd, & table_list,
+                                       & open_tables_backup);
+  need_close= true;
+
+  if (!table ||
+      table->file->extra(HA_EXTRA_MARK_AS_LOG_TABLE) ||
+      table->file->ha_rnd_init(0))
+    goto err;
+
+  need_rnd_end= true;
+
+  /* Honor next number columns if present */
+  table->next_number_field= table->found_next_number_field;
 
-  /*
-     Set start time for CURRENT_TIMESTAMP to the start of the query.
-     This will be default value for the field[0]
-  */
-  slow_log_thd->start_time= query_start_arg;
   restore_record(table, s->default_values);    // Get empty record
 
+  /* check that all columns exist */
+  if (table->s->fields < 11)
+    goto err;
+
   /*
     We do not set a value for table->field[0], as it will use
     default value.
   */
 
-  if (!table->field[1] || !table->field[2] || !table->field[3] ||
-      !table->field[4] || !table->field[5] || !table->field[6] ||
-      !table->field[7] || !table->field[8] || !table->field[9] ||
-      !table->field[10])
-    goto err;
-
   /* store the value */
   if (table->field[1]->store(user_host, user_host_len, client_cs))
     goto err;
@@ -612,7 +556,6 @@ bool Log_to_csv_event_handler::
     table->field[4]->set_null();
     table->field[5]->set_null();
   }
-
   /* fill database field */
   if (thd->db)
   {
@@ -655,18 +598,67 @@ bool Log_to_csv_event_handler::
     goto err;
 
   /* log table entries are not replicated at the moment */
-  tmp_disable_binlog(current_thd);
-
-  /* write the row */
-  table->file->ha_write_row(table->record[0]);
+  tmp_disable_binlog(thd);
+  table->file->ha_write_row_no_binlog(table->record[0]);
+  reenable_binlog(thd);
 
-  reenable_binlog(current_thd);
+  result= false;
 
-  DBUG_RETURN(0);
 err:
-  DBUG_RETURN(1);
+  if (need_rnd_end)
+  {
+    table->file->ha_rnd_end();
+    table->file->ha_release_auto_increment();
+  }
+  if (need_close)
+    close_performance_schema_table(thd, & open_tables_backup);
+
+  thd->query_start_used= save_query_start_used;
+  thd->start_time= save_start_time;
+  thd->time_after_lock= save_time_after_lock;
+  thd->user_time= save_user_time;
+  thd->time_zone_used= save_time_zone_used;
+  DBUG_RETURN(result);
+}
+
+
+int Log_to_csv_event_handler::
+  activate_log(THD *thd, uint log_table_type)
+{
+  TABLE_LIST table_list;
+  TABLE *table;
+  int result;
+  Open_tables_state open_tables_backup;
+
+  DBUG_ENTER("Log_to_csv_event_handler::activate_log");
+
+  bzero(& table_list, sizeof(TABLE_LIST));
+
+  if (log_table_type == QUERY_LOG_GENERAL)
+  {
+    table_list.alias= table_list.table_name= GENERAL_LOG_NAME.str;
+    table_list.table_name_length= GENERAL_LOG_NAME.length;
+  }
+  else
+  {
+    DBUG_ASSERT(log_table_type == QUERY_LOG_SLOW);
+    table_list.alias= table_list.table_name= SLOW_LOG_NAME.str;
+    table_list.table_name_length= SLOW_LOG_NAME.length;
+  }
+
+  table_list.lock_type= TL_WRITE_CONCURRENT_INSERT;
+
+  table_list.db= MYSQL_SCHEMA_NAME.str;
+  table_list.db_length= MYSQL_SCHEMA_NAME.length;
+
+  table= open_performance_schema_table(thd, & table_list,
+                                       & open_tables_backup);
+  result= (table ? 0 : 1);
+  close_performance_schema_table(thd, & open_tables_backup);
+  DBUG_RETURN(result);
 }
 
+
 bool Log_to_csv_event_handler::
   log_error(enum loglevel level, const char *format, va_list args)
 {
@@ -710,7 +702,7 @@ bool Log_to_file_event_handler::
 */
 
 bool Log_to_file_event_handler::
-  log_general(time_t event_time, const char *user_host,
+  log_general(THD *thd, time_t event_time, const char *user_host,
               uint user_host_len, int thread_id,
               const char *command_type, uint command_type_len,
               const char *sql_text, uint sql_text_len,
@@ -806,12 +798,6 @@ void LOGGER::cleanup_end()
 }
 
 
-void LOGGER::close_log_table(uint log_table_type, bool lock_in_use)
-{
-  table_log_handler->close_log_table(log_table_type, lock_in_use);
-}
-
-
 /*
   Perform basic log initialization: create file-based log handler and
   init error log.
@@ -848,29 +834,6 @@ void LOGGER::init_log_tables()
 }
 
 
-bool LOGGER::reopen_log_table(uint log_table_type)
-{
-  return table_log_handler->reopen_log_table(log_table_type);
-}
-
-bool LOGGER::reopen_log_tables()
-{
-    /*
-      we use | and not || here, to ensure that both reopen_log_table
-      are called, even if the first one fails
-    */
-    if ((opt_slow_log && logger.reopen_log_table(QUERY_LOG_SLOW)) |
-        (opt_log && logger.reopen_log_table(QUERY_LOG_GENERAL)))
-      return TRUE;
-    return FALSE;
-}
-
-
-void LOGGER::tmp_close_log_tables(THD *thd)
-{
-  table_log_handler->tmp_close_log_tables(thd);
-}
-
 bool LOGGER::flush_logs(THD *thd)
 {
   int rc= 0;
@@ -880,18 +843,10 @@ bool LOGGER::flush_logs(THD *thd)
     log tables are closed
   */
   logger.lock();
-  if (logger.is_log_tables_initialized)
-    table_log_handler->tmp_close_log_tables(thd); // the locking happens here
 
   /* reopen log files */
   file_log_handler->flush();
 
-  /* reopen tables in the case they were enabled */
-  if (logger.is_log_tables_initialized)
-  {
-    if (reopen_log_tables())
-      rc= TRUE;
-  }
   /* end of log flush */
   logger.unlock();
   return rc;
@@ -1035,7 +990,7 @@ bool LOGGER::general_log_print(THD *thd,
 
     while (*current_handler)
       error+= (*current_handler++)->
-        log_general(current_time, user_host_buff,
+        log_general(thd, current_time, user_host_buff,
                    user_host_len, id,
                    command_name[(uint) command].str,
                    command_name[(uint) command].length,
@@ -1122,35 +1077,42 @@ void LOGGER::init_general_log(uint gener
 
 bool LOGGER::activate_log_handler(THD* thd, uint log_type)
 {
-  bool res= 0;
+  bool res= false;
   lock();
   switch (log_type) {
   case QUERY_LOG_SLOW:
     if (!opt_slow_log)
     {
-      if ((res= reopen_log_table(log_type)))
-        goto err;
       file_log_handler->get_mysql_slow_log()->
         open_slow_log(sys_var_slow_log_path.value);
       init_slow_log(log_output_options);
-      opt_slow_log= TRUE;
+      if (table_log_handler->activate_log(thd, QUERY_LOG_SLOW))
+      {
+        /* Error printed by open table in activate_log() */
+        res= true;
+      }
+      else
+        opt_slow_log= TRUE;
     }
     break;
   case QUERY_LOG_GENERAL:
     if (!opt_log)
     {
-      if ((res= reopen_log_table(log_type)))
-        goto err;
       file_log_handler->get_mysql_log()->
         open_query_log(sys_var_general_log_path.value);
       init_general_log(log_output_options);
-      opt_log= TRUE;
+      if (table_log_handler->activate_log(thd, QUERY_LOG_GENERAL))
+      {
+        /* Error printed by open table in activate_log() */
+        res= true;
+      }
+      else
+        opt_log= TRUE;
     }
     break;
   default:
     DBUG_ASSERT(0);
   }
-err:
   unlock();
   return res;
 }
@@ -1158,23 +1120,17 @@ err:
 
 void LOGGER::deactivate_log_handler(THD *thd, uint log_type)
 {
-  TABLE_LIST *table_list;
   my_bool *tmp_opt= 0;
   MYSQL_LOG *file_log;
-  THD *log_thd;
 
   switch (log_type) {
   case QUERY_LOG_SLOW:
-    table_list= &table_log_handler->slow_log;
     tmp_opt= &opt_slow_log;
     file_log= file_log_handler->get_mysql_slow_log();
-    log_thd= table_log_handler->slow_log_thd;
     break;
   case QUERY_LOG_GENERAL:
-    table_list= &table_log_handler->general_log;
     tmp_opt= &opt_log;
     file_log= file_log_handler->get_mysql_log();
-    log_thd= table_log_handler->general_log_thd;
     break;
   default:
     assert(0);                                  // Impossible
@@ -1183,81 +1139,17 @@ void LOGGER::deactivate_log_handler(THD 
   if (!(*tmp_opt))
     return;
 
-  if (is_log_tables_initialized)
-    lock_and_wait_for_table_name(log_thd, table_list);
   lock();
 
-  if (is_log_tables_initialized)
-  {
-    VOID(pthread_mutex_lock(&LOCK_open));
-    close_log_table(log_type, TRUE);
-    table_list->table= 0;
-    query_cache_invalidate3(log_thd, table_list, 0);
-    unlock_table_name(log_thd, table_list);
-    VOID(pthread_mutex_unlock(&LOCK_open));
-  }
   file_log->close(0);
   *tmp_opt= FALSE;
   unlock();
 }
 
 
-/*
-  Close log tables temporarily. The thread which closed
-  them this way can lock them in any mode it needs.
-  NOTE: one should call logger.lock() before entering this
-  function.
-*/
-void Log_to_csv_event_handler::tmp_close_log_tables(THD *thd)
-{
-  TABLE_LIST close_slow_log, close_general_log;
-
-  /* fill lists, we will need to perform operations on tables */
-  bzero((char*) &close_slow_log, sizeof(TABLE_LIST));
-  close_slow_log.alias= close_slow_log.table_name=(char*) "slow_log";
-  close_slow_log.table_name_length= 8;
-  close_slow_log.db= (char*) "mysql";
-  close_slow_log.db_length= 5;
-
-  bzero((char*) &close_general_log, sizeof(TABLE_LIST));
-  close_general_log.alias= close_general_log.table_name=(char*) "general_log";
-  close_general_log.table_name_length= 11;
-  close_general_log.db= (char*) "mysql";
-  close_general_log.db_length= 5;
-
-  privileged_thread= thd;
-
-  VOID(pthread_mutex_lock(&LOCK_open));
-  /*
-    NOTE: in fact, the first parameter used in query_cache_invalidate3()
-    could be any non-NULL THD, as the underlying code makes certain
-    assumptions about this.
-    Here we use one of the logger handler THD's. Simply because it
-    seems appropriate.
-  */
-  if (opt_log)
-  {
-    close_log_table(QUERY_LOG_GENERAL, TRUE);
-    query_cache_invalidate3(general_log_thd, &close_general_log, 0);
-  }
-  if (opt_slow_log)
-  {
-    close_log_table(QUERY_LOG_SLOW, TRUE);
-    query_cache_invalidate3(general_log_thd, &close_slow_log, 0);
-  }
-  VOID(pthread_mutex_unlock(&LOCK_open));
-}
-
 /* the parameters are unused for the log tables */
 bool Log_to_csv_event_handler::init()
 {
-  /*
-    we use | and not || here, to ensure that both open_log_table
-    are called, even if the first one fails
-  */
-  if ((opt_log && open_log_table(QUERY_LOG_GENERAL)) |
-      (opt_slow_log && open_log_table(QUERY_LOG_SLOW)))
-    return 1;
   return 0;
 }
 
@@ -1287,72 +1179,6 @@ int LOGGER::set_handlers(uint error_log_
   unlock();
 
   return 0;
-}
-
-
-/*
-  Close log table of a given type (general or slow log)
-
-  SYNOPSIS
-    close_log_table()
-
-    log_table_type   type of the log table to close: QUERY_LOG_GENERAL
-                     or QUERY_LOG_SLOW
-    lock_in_use      Set to TRUE if the caller owns LOCK_open. FALSE otherwise.
-
-  DESCRIPTION
-
-    The function closes a log table. It is invoked (1) when we need to reopen
-    log tables (e.g. FLUSH LOGS or TRUNCATE on the log table is being
-    executed) or (2) during shutdown.
-*/
-
-void Log_to_csv_event_handler::
-  close_log_table(uint log_table_type, bool lock_in_use)
-{
-  THD *log_thd, *curr= current_thd;
-  TABLE_LIST *table;
-
-  if (!logger.is_log_table_enabled(log_table_type))
-    return;                                     /* do nothing */
-
-  switch (log_table_type) {
-  case QUERY_LOG_GENERAL:
-    log_thd= general_log_thd;
-    table= &general_log;
-    break;
-  case QUERY_LOG_SLOW:
-    log_thd= slow_log_thd;
-    table= &slow_log;
-    break;
-  default:
-    assert(0);                                  // Impossible
-  }
-
-  /*
-    Set thread stack start for the logger thread. See comment in
-    open_log_table() for details.
-  */
-  if (curr)
-    log_thd->thread_stack= curr->thread_stack;
-  else
-    log_thd->thread_stack= (char*) &log_thd;
-
-  /* close the table */
-  log_thd->store_globals();
-  table->table->file->ha_rnd_end();
-  table->table->file->ha_release_auto_increment();
-  /* discard logger mark before unlock*/
-  table->table->locked_by_logger= FALSE;
-  close_thread_tables(log_thd, lock_in_use);
-
-  if (curr)
-    curr->store_globals();
-  else
-  {
-    my_pthread_setspecific_ptr(THR_THD,  0);
-    my_pthread_setspecific_ptr(THR_MALLOC, 0);
-  }
 }
 
 
diff -Nrup a/sql/log.h b/sql/log.h
--- a/sql/log.h	2007-06-16 22:56:31 -06:00
+++ b/sql/log.h	2007-07-19 19:43:10 -06:00
@@ -398,7 +398,7 @@ public:
                         const char *sql_text, uint sql_text_len)= 0;
   virtual bool log_error(enum loglevel level, const char *format,
                          va_list args)= 0;
-  virtual bool log_general(time_t event_time, const char *user_host,
+  virtual bool log_general(THD *thd, time_t event_time, const char *user_host,
                            uint user_host_len, int thread_id,
                            const char *command_type, uint command_type_len,
                            const char *sql_text, uint sql_text_len,
@@ -412,27 +412,7 @@ int check_if_log_table(uint db_len, cons
 
 class Log_to_csv_event_handler: public Log_event_handler
 {
-  /*
-    We create artificial THD for each of the logs. This is to avoid
-    locking issues: we don't want locks on the log tables reside in the
-    THD's of the query. The reason is the locking order and duration.
-  */
-  THD *general_log_thd, *slow_log_thd;
-  /*
-    This is for the thread, which called tmp_close_log_tables. The thread
-    will be allowed to write-lock the log tables (as it explicitly disabled
-    logging). This is used for such operations as REPAIR, which require
-    exclusive lock on the log tables.
-    NOTE: there can be only one priviliged thread, as one should
-    lock logger with logger.lock() before calling tmp_close_log_tables().
-    So no other thread could get privileged status at the same time.
-  */
-  THD *privileged_thread;
   friend class LOGGER;
-  TABLE_LIST general_log, slow_log;
-
-private:
-  bool open_log_table(uint log_type);
 
 public:
   Log_to_csv_event_handler();
@@ -447,18 +427,13 @@ public:
                         const char *sql_text, uint sql_text_len);
   virtual bool log_error(enum loglevel level, const char *format,
                          va_list args);
-  virtual bool log_general(time_t event_time, const char *user_host,
+  virtual bool log_general(THD *thd, time_t event_time, const char *user_host,
                            uint user_host_len, int thread_id,
                            const char *command_type, uint command_type_len,
                            const char *sql_text, uint sql_text_len,
-                            CHARSET_INFO *client_cs);
-  void tmp_close_log_tables(THD *thd);
-  void close_log_table(uint log_type, bool lock_in_use);
-  bool reopen_log_table(uint log_type);
-  THD* get_privileged_thread()
-  {
-    return privileged_thread;
-  }
+                           CHARSET_INFO *client_cs);
+
+  int activate_log(THD *thd, uint log_type);
 };
 
 
@@ -484,7 +459,7 @@ public:
                         const char *sql_text, uint sql_text_len);
   virtual bool log_error(enum loglevel level, const char *format,
                          va_list args);
-  virtual bool log_general(time_t event_time, const char *user_host,
+  virtual bool log_general(THD *thd, time_t event_time, const char *user_host,
                            uint user_host_len, int thread_id,
                            const char *command_type, uint command_type_len,
                            const char *sql_text, uint sql_text_len,
@@ -521,19 +496,7 @@ public:
   {}
   void lock() { (void) pthread_mutex_lock(&LOCK_logger); }
   void unlock() { (void) pthread_mutex_unlock(&LOCK_logger); }
-  void tmp_close_log_tables(THD *thd);
-  bool is_log_table_enabled(uint log_table_type)
-  {
-    switch (log_table_type) {
-    case QUERY_LOG_SLOW:
-      return table_log_handler && table_log_handler->slow_log.table != 0;
-    case QUERY_LOG_GENERAL:
-      return table_log_handler && table_log_handler->general_log.table != 0;
-    default:
-      DBUG_ASSERT(0);
-      return FALSE;                             /* make compiler happy */
-    }
-  }
+  bool is_log_table_enabled(uint log_table_type);
   /*
     We want to initialize all log mutexes as soon as possible,
     but we cannot do it in constructor, as safe_mutex relies on
@@ -543,20 +506,6 @@ public:
   void init_base();
   void init_log_tables();
   bool flush_logs(THD *thd);
-  THD *get_general_log_thd()
-  {
-    if (table_log_handler)
-      return (THD *) table_log_handler->general_log_thd;
-    else
-      return NULL;
-  }
-  THD *get_slow_log_thd()
-  {
-    if (table_log_handler)
-      return (THD *) table_log_handler->slow_log_thd;
-    else
-      return NULL;
-  }
   /* Perform basic logger cleanup. this will leave e.g. error log open. */
   void cleanup_base();
   /* Free memory. Nothing could be logged after this function is called */
@@ -568,10 +517,6 @@ public:
   bool general_log_print(THD *thd,enum enum_server_command command,
                          const char *format, va_list args);
 
-  void close_log_table(uint log_type, bool lock_in_use);
-  bool reopen_log_table(uint log_type);
-  bool reopen_log_tables();
-
   /* we use this function to setup all enabled log event handlers */
   int set_handlers(uint error_log_printer,
                    uint slow_log_printer,
@@ -592,19 +537,6 @@ public:
     if (file_log_handler)
       return file_log_handler->get_mysql_log();
     return NULL;
-  }
-  THD* get_privileged_thread()
-  {
-    if (table_log_handler)
-      return table_log_handler->get_privileged_thread();
-    else
-      return NULL;
-  }
-  bool is_privileged_thread(THD *thd)
-  {
-    return thd == get_general_log_thd() ||
-           thd == get_slow_log_thd() ||
-           thd == get_privileged_thread();
   }
 };
 
diff -Nrup a/sql/mysql_priv.h b/sql/mysql_priv.h
--- a/sql/mysql_priv.h	2007-06-21 13:02:10 -06:00
+++ b/sql/mysql_priv.h	2007-07-19 19:43:10 -06:00
@@ -355,6 +355,13 @@ MY_LOCALE *my_locale_by_number(uint numb
 */
 #define TMP_TABLE_FORCE_MYISAM          (ULL(1) << 32)
 
+/*
+  Privileged thread, that can perform operations on
+  privileged tables (as defined by require_write_privileges()).
+  Currently, this flag is used to control locking / writing
+  to the mysql.general_log and mysql.slow_log tables.
+*/
+#define OPTION_INTERNAL_PRIVILEGE (ULL(1) << 33) // THD, intern
 
 /*
   Maximum length of time zone name that we support
@@ -1121,6 +1128,11 @@ void reset_status_vars();
 
 /* information schema */
 extern LEX_STRING INFORMATION_SCHEMA_NAME;
+/* log tables */
+extern LEX_STRING MYSQL_SCHEMA_NAME;
+extern LEX_STRING GENERAL_LOG_NAME;
+extern LEX_STRING SLOW_LOG_NAME;
+
 extern const LEX_STRING partition_keywords[];
 LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str,
                             const char* str, uint length,
@@ -1450,6 +1462,10 @@ bool open_system_tables_for_read(THD *th
 void close_system_tables(THD *thd, Open_tables_state *backup);
 TABLE *open_system_table_for_update(THD *thd, TABLE_LIST *one_table);
 
+TABLE *open_performance_schema_table(THD *thd, TABLE_LIST *one_table,
+                                     Open_tables_state *backup);
+void close_performance_schema_table(THD *thd, Open_tables_state *backup);
+
 bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables, bool have_lock = FALSE);
 bool close_cached_connection_tables(THD *thd, bool wait_for_refresh,
                                     LEX_STRING *connect_string,
@@ -1769,7 +1785,6 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, 
 #define MYSQL_LOCK_IGNORE_FLUSH                 0x0002
 #define MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN        0x0004
 #define MYSQL_OPEN_TEMPORARY_ONLY               0x0008
-#define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY      0x0010
 
 void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
 void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
diff -Nrup a/sql/set_var.cc b/sql/set_var.cc
--- a/sql/set_var.cc	2007-06-18 04:09:22 -06:00
+++ b/sql/set_var.cc	2007-07-19 19:43:10 -06:00
@@ -2051,21 +2051,15 @@ end:
 
 bool sys_var_log_state::update(THD *thd, set_var *var)
 {
-  bool res= 0;
+  bool res;
   pthread_mutex_lock(&LOCK_global_system_variables);
   if (!var->save_result.ulong_value)
-    logger.deactivate_log_handler(thd, log_type);
-  else
   {
-    if ((res= logger.activate_log_handler(thd, log_type)))
-    {
-      my_error(ER_CANT_ACTIVATE_LOG, MYF(0),
-               log_type == QUERY_LOG_GENERAL ? "general" :
-               "slow query");
-      goto err;
-    }
+    logger.deactivate_log_handler(thd, log_type);
+    res= false;
   }
-err:
+  else
+    res= logger.activate_log_handler(thd, log_type);
   pthread_mutex_unlock(&LOCK_global_system_variables);
   return res;
 }
diff -Nrup a/sql/share/errmsg.txt b/sql/share/errmsg.txt
--- a/sql/share/errmsg.txt	2007-06-18 04:10:32 -06:00
+++ b/sql/share/errmsg.txt	2007-07-19 19:43:11 -06:00
@@ -5908,7 +5908,7 @@ ER_CANT_WRITE_LOCK_LOG_TABLE
         eng "You can't write-lock a log table. Only read access is possible"
         ger "Eine Log-Tabelle kann nicht schreibgesperrt werden. Es ist ohnehin nur Lesezugriff mglich"
 ER_CANT_READ_LOCK_LOG_TABLE
-        eng "You can't use usual read lock with log tables. Try READ LOCAL instead"
+        eng "You can't use locks with log tables."
         ger "Log-Tabellen knnen nicht mit normalen Lesesperren gesperrt werden. Verwenden Sie statt dessen READ LOCAL"
 ER_FOREIGN_DUPLICATE_KEY 23000 S1009
         eng "Upholding foreign key constraints for table '%.192s', entry '%-.192s', key %d would lead to a duplicate entry"
diff -Nrup a/sql/sql_base.cc b/sql/sql_base.cc
--- a/sql/sql_base.cc	2007-06-21 13:02:11 -06:00
+++ b/sql/sql_base.cc	2007-07-19 19:43:10 -06:00
@@ -900,8 +900,7 @@ bool close_cached_tables(THD *thd, bool 
     bool found=0;
     for (TABLE_LIST *table= tables; table; table= table->next_local)
     {
-      if ((!table->table || !table->table->s->log_table) &&
-          remove_table_from_cache(thd, table->db, table->table_name,
+      if (remove_table_from_cache(thd, table->db, table->table_name,
                                   RTFC_OWNED_BY_THD_FLAG))
 	found=1;
     }
@@ -949,8 +948,7 @@ bool close_cached_tables(THD *thd, bool 
           are employed by CREATE TABLE as in this case table simply does not
           exist yet.
         */
-	if (!table->s->log_table &&
-            (table->needs_reopen_or_name_lock() && table->db_stat))
+	if (table->needs_reopen_or_name_lock() && table->db_stat)
 	{
 	  found=1;
           DBUG_PRINT("signal", ("Waiting for COND_refresh"));
@@ -2393,18 +2391,37 @@ TABLE *open_table(THD *thd, TABLE_LIST *
         VOID(pthread_mutex_unlock(&LOCK_open));
       }
     }
+
+    LEX_STRING db;
+    LEX_STRING alias;
+    db.str= table_list->db;
+    db.length= strlen(table_list->db);
+    alias.str= table_list->alias;
+    alias.length= strlen(table_list->alias);
+    TABLE_CATEGORY table_category= get_table_category(& db, & alias);
+
     /*
-      No table in the locked tables list. In case of explicit LOCK TABLES
-      this can happen if a user did not include the able into the list.
-      In case of pre-locked mode locked tables list is generated automatically,
-      so we may only end up here if the table did not exist when
-      locked tables list was created.
+      Since we don't want to allow explicit LOCK TABLES on performance schema
+      tables, the code falls through and we open these tables from the cache,
+      even under a LOCK TABLES. This does not cause a dead lock, because
+      manipulating TABLE_CATEGORY_PERFORMANCE tables is very restricted.
     */
-    if (thd->prelocked_mode == PRELOCKED)
-      my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
-    else
-      my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
-    DBUG_RETURN(0);
+    if (table_category != TABLE_CATEGORY_PERFORMANCE)
+    {
+      /*
+        No table in the locked tables list. In case of explicit LOCK TABLES
+        this can happen if a user did not include the able into the list.
+        In case of pre-locked mode locked tables list is generated automatically,
+        so we may only end up here if the table did not exist when
+        locked tables list was created.
+      */
+
+      if (thd->prelocked_mode == PRELOCKED)
+        my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
+      else
+        my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
+      DBUG_RETURN(0);
+    }
   }
 
   /*
@@ -2466,8 +2483,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
                                  &state))
   {
     /*
-      Here we flush tables marked for flush. However we never flush log
-      tables here. They are flushed only on FLUSH LOGS.
+      Here we flush tables marked for flush.
       Normally, table->s->version contains the value of
       refresh_version from the moment when this table was
       (re-)opened and added to the cache.
@@ -2484,7 +2500,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *
       c1: name lock t2; -- blocks
       c2: open t1; -- blocks
     */
-    if (table->needs_reopen_or_name_lock() && !table->s->log_table)
+    if (table->needs_reopen_or_name_lock())
     {
       DBUG_PRINT("note",
                  ("Found table '%s.%s' with different refresh version",
@@ -2960,10 +2976,9 @@ void close_old_data_files(THD *thd, TABL
   for (; table ; table=table->next)
   {
     /*
-      Reopen marked for flush. But close log tables. They are flushed only
-      explicitly on FLUSH LOGS
+      Reopen marked for flush.
     */
-    if (table->needs_reopen_or_name_lock() && !table->s->log_table)
+    if (table->needs_reopen_or_name_lock())
     {
       found=1;
       if (table->db_stat)
@@ -3010,10 +3025,6 @@ void close_old_data_files(THD *thd, TABL
   Wait until all threads has closed the tables in the list
   We have also to wait if there is thread that has a lock on this table even
   if the table is closed
-  NOTE: log tables are handled differently by the logging routines.
-        E.g. general_log is always opened and locked by the logger
-        and the table handler used by the logger, will be skipped by
-        this check.
 */
 
 bool table_is_used(TABLE *table, bool wait_for_name_lock)
@@ -3032,10 +3043,10 @@ bool table_is_used(TABLE *table, bool wa
          search= (TABLE*) hash_next(&open_cache, (uchar*) key,
                                     key_length, &state))
     {
-      DBUG_PRINT("info", ("share: 0x%lx  locked_by_logger: %d "
+      DBUG_PRINT("info", ("share: 0x%lx  "
                           "open_placeholder: %d  locked_by_name: %d "
                           "db_stat: %u  version: %lu",
-                          (ulong) search->s, search->locked_by_logger,
+                          (ulong) search->s,
                           search->open_placeholder, search->locked_by_name,
                           search->db_stat,
                           search->s->version));
@@ -3047,12 +3058,9 @@ bool table_is_used(TABLE *table, bool wa
         - If we are in flush table and we didn't execute the flush
         - If the table engine is open and it's an old version
         (We must wait until all engines are shut down to use the table)
-        However we fo not wait if we encountered a table, locked by the logger.
-        Log tables are managed separately by logging routines.
       */
-      if (!search->locked_by_logger &&
-          (search->locked_by_name && wait_for_name_lock ||
-           (search->is_name_opened() && search->needs_reopen_or_name_lock())))
+      if ( (search->locked_by_name && wait_for_name_lock) ||
+           (search->is_name_opened() && search->needs_reopen_or_name_lock()))
         DBUG_RETURN(1);
     }
   } while ((table=table->next));
@@ -4127,11 +4135,6 @@ int lock_tables(THD *thd, TABLE_LIST *ta
     DBUG_ASSERT(thd->lock == 0);	// You must lock everything at once
     TABLE **start,**ptr;
     uint lock_flag= MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN;
-    
-    /* Ignore GLOBAL READ LOCK and GLOBAL READ_ONLY if called from a logger */
-    if (logger.is_privileged_thread(thd))
-      lock_flag|= (MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK |
-                   MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY);
 
     if (!(ptr=start=(TABLE**) thd->alloc(sizeof(TABLE*)*count)))
       DBUG_RETURN(-1);
@@ -7160,7 +7163,6 @@ bool remove_table_from_cache(THD *thd, c
       else if (in_use != thd)
       {
         DBUG_PRINT("info", ("Table was in use by other thread"));
-        in_use->some_tables_deleted=1;
         if (table->is_name_opened())
         {
           DBUG_PRINT("info", ("Found another active instance of the table"));
@@ -7596,7 +7598,7 @@ open_system_tables_for_read(THD *thd, TA
     if (!table)
       goto error;
 
-    DBUG_ASSERT(table->s->system_table);
+    DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_SYSTEM);
 
     table->use_all_columns();
     table->reginfo.lock_type= tables->lock_type;
@@ -7666,9 +7668,72 @@ open_system_table_for_update(THD *thd, T
   TABLE *table= open_ltable(thd, one_table, one_table->lock_type);
   if (table)
   {
-    DBUG_ASSERT(table->s->system_table);
+    DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_SYSTEM);
+    table->use_all_columns();
+  }
+
+  DBUG_RETURN(table);
+}
+
+TABLE *
+open_performance_schema_table(THD *thd, TABLE_LIST *one_table,
+                              Open_tables_state *backup)
+{
+  DBUG_ENTER("open_performance_schema_table");
+
+  thd->reset_n_backup_open_tables_state(backup);
+
+  DBUG_ASSERT((thd->options & OPTION_INTERNAL_PRIVILEGE) == 0);
+  thd->options|= OPTION_INTERNAL_PRIVILEGE;
+
+  TABLE *table= open_ltable(thd, one_table, one_table->lock_type);
+  if (table)
+  {
+    DBUG_ASSERT(table->s->table_category == TABLE_CATEGORY_PERFORMANCE);
     table->use_all_columns();
+    table->no_replicate= TRUE;
+    table->s->cached_row_logging_check= 0;
   }
 
+  thd->options&= ~OPTION_INTERNAL_PRIVILEGE;
   DBUG_RETURN(table);
 }
+
+void close_performance_schema_table(THD *thd, Open_tables_state *backup)
+{
+  bool found_old_table;
+
+  if (thd->lock)
+  {
+    /*
+      Note:
+      We do not create explicitly a separate transaction for the
+      performance table I/O, but borrow the current transaction.
+      lock + unlock will autocommit the change done in the
+      performance schema table: this is the expected result.
+      The current transaction should not be affected by this code.
+      TODO: Consider doing a backup of THD::transaction and THD::ha_data
+      in Open_tables_state, to better isolate this.
+    */
+    mysql_unlock_tables(thd, thd->lock);
+    thd->lock= 0;
+  }
+
+  safe_mutex_assert_not_owner(&LOCK_open);
+
+  pthread_mutex_lock(&LOCK_open);
+
+  mysql_ha_mark_tables_for_reopen(thd, thd->open_tables);
+
+  found_old_table= false;
+  while (thd->open_tables)
+    found_old_table|= close_thread_table(thd, &thd->open_tables);
+
+  if (found_old_table)
+    broadcast_refresh();
+
+  pthread_mutex_unlock(&LOCK_open);
+
+  thd->restore_backup_open_tables_state(backup);
+}
+
diff -Nrup a/sql/sql_delete.cc b/sql/sql_delete.cc
--- a/sql/sql_delete.cc	2007-06-24 16:33:23 -06:00
+++ b/sql/sql_delete.cc	2007-07-19 19:43:10 -06:00
@@ -900,16 +900,14 @@ bool multi_delete::send_eof()
   - If we want to have a name lock on the table on exit without errors.
 */
 
-bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
+bool mysql_truncate_impl(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
 {
   HA_CREATE_INFO create_info;
   char path[FN_REFLEN];
   TABLE *table;
   bool error;
-  uint closed_log_tables= 0, lock_logger= 0;
   uint path_length;
-  uint log_type;
-  DBUG_ENTER("mysql_truncate");
+  DBUG_ENTER("mysql_truncate_impl");
 
   bzero((char*) &create_info,sizeof(create_info));
   /* If it is a temporary table, close and regenerate it */
@@ -960,18 +958,6 @@ bool mysql_truncate(THD *thd, TABLE_LIST
       DBUG_RETURN(TRUE);
   }
 
-  log_type= check_if_log_table(table_list->db_length, table_list->db,
-                               table_list->table_name_length,
-                               table_list->table_name, 1);
-  /* close log tables in use */
-  if (log_type)
-  {
-    lock_logger= 1;
-    logger.lock();
-    logger.close_log_table(log_type, FALSE);
-    closed_log_tables= closed_log_tables | log_type;
-  }
-
   // Remove the .frm extension AIX 5.2 64-bit compiler bug (BUG#16155): this
   // crashes, replacement works.  *(path + path_length - reg_ext_length)=
   // '\0';
@@ -997,14 +983,6 @@ end:
     VOID(pthread_mutex_lock(&LOCK_open));
     unlock_table_name(thd, table_list);
     VOID(pthread_mutex_unlock(&LOCK_open));
-
-    if (opt_slow_log && (closed_log_tables & QUERY_LOG_SLOW))
-      logger.reopen_log_table(QUERY_LOG_SLOW);
-
-    if (opt_log && (closed_log_tables & QUERY_LOG_GENERAL))
-      logger.reopen_log_table(QUERY_LOG_GENERAL);
-    if (lock_logger)
-      logger.unlock();
   }
   else if (error)
   {
@@ -1030,3 +1008,29 @@ trunc_by_del:
   thd->current_stmt_binlog_row_based= save_binlog_row_based;
   DBUG_RETURN(error);
 }
+
+
+bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
+{
+  uint log_type;
+  bool result;
+
+  log_type= check_if_log_table(table_list->db_length, table_list->db,
+                               table_list->table_name_length,
+                               table_list->table_name, 0);
+  if (log_type)
+  {
+    DBUG_ASSERT((thd->options & OPTION_INTERNAL_PRIVILEGE) == 0);
+    thd->options|= OPTION_INTERNAL_PRIVILEGE;
+  }
+
+  result= mysql_truncate_impl(thd, table_list, dont_send_ok);
+
+  if (log_type)
+  {
+    thd->options&= ~OPTION_INTERNAL_PRIVILEGE;
+  }
+
+  return result;
+}
+
diff -Nrup a/sql/sql_error.cc b/sql/sql_error.cc
--- a/sql/sql_error.cc	2007-06-07 02:39:27 -06:00
+++ b/sql/sql_error.cc	2007-07-19 19:43:10 -06:00
@@ -137,6 +137,9 @@ MYSQL_ERROR *push_warning(THD *thd, MYSQ
     level= MYSQL_ERROR::WARN_LEVEL_ERROR;
   }
 
+  if (thd->handle_error(code, level))
+    DBUG_RETURN(NULL);
+
   if (thd->spcont &&
       thd->spcont->handle_error(code, level, thd))
   {
diff -Nrup a/sql/sql_rename.cc b/sql/sql_rename.cc
--- a/sql/sql_rename.cc	2007-06-19 05:27:52 -06:00
+++ b/sql/sql_rename.cc	2007-07-19 19:43:11 -06:00
@@ -37,7 +37,6 @@ bool mysql_rename_tables(THD *thd, TABLE
   TABLE_LIST *ren_table= 0;
   int to_table;
   char *rename_log_table[2]= {NULL, NULL};
-  int disable_logs= 0;
   DBUG_ENTER("mysql_rename_tables");
 
   /*
@@ -80,12 +79,6 @@ bool mysql_rename_tables(THD *thd, TABLE
                               ren_table->table_name, 1)))
       {
         /*
-          Log table encoutered we will need to disable and lock logs
-          for duration of rename.
-        */
-        disable_logs= TRUE;
-
-        /*
           as we use log_table_rename as an array index, we need it to start
           with 0, while QUERY_LOG_SLOW == 1 and QUERY_LOG_GENERAL == 2.
           So, we shift the value to start with 0;
@@ -136,12 +129,6 @@ bool mysql_rename_tables(THD *thd, TABLE
                  rename_log_table[1]);
       DBUG_RETURN(1);
     }
-
-    if (disable_logs)
-    {
-      logger.lock();
-      logger.tmp_close_log_tables(thd);
-    }
   }
 
   VOID(pthread_mutex_lock(&LOCK_open));
@@ -182,13 +169,6 @@ bool mysql_rename_tables(THD *thd, TABLE
 
 err:
   pthread_mutex_unlock(&LOCK_open);
-  /* enable logging back if needed */
-  if (disable_logs)
-  {
-    if (logger.reopen_log_tables())
-      error= TRUE;
-    logger.unlock();
-  }
   start_waiting_global_read_lock(thd);
   DBUG_RETURN(error);
 }
diff -Nrup a/sql/sql_select.cc b/sql/sql_select.cc
--- a/sql/sql_select.cc	2007-06-24 20:06:04 -06:00
+++ b/sql/sql_select.cc	2007-07-19 19:43:11 -06:00
@@ -2451,7 +2451,7 @@ make_join_statistics(JOIN *join, TABLE_L
 #else
     const bool no_partitions_used= FALSE;
 #endif
-    if ((table->s->system || table->file->stats.records <= 1 ||
+    if ((table->s->one_record_table || table->file->stats.records <= 1 ||
          no_partitions_used) &&
 	!s->dependent &&
 	(table->file->ha_table_flags() & HA_STATS_RECORDS_IS_EXACT) &&
diff -Nrup a/sql/sql_show.cc b/sql/sql_show.cc
--- a/sql/sql_show.cc	2007-06-14 05:37:50 -06:00
+++ b/sql/sql_show.cc	2007-07-19 19:43:11 -06:00
@@ -2166,9 +2166,6 @@ LEX_STRING *make_lex_string(THD *thd, LE
 }
 
 
-/* INFORMATION_SCHEMA name */
-LEX_STRING INFORMATION_SCHEMA_NAME= { C_STRING_WITH_LEN("information_schema")};
-
 /* This is only used internally, but we need it here as a forward reference */
 extern ST_SCHEMA_TABLE schema_tables[];
 
diff -Nrup a/sql/sql_table.cc b/sql/sql_table.cc
--- a/sql/sql_table.cc	2007-06-19 05:01:05 -06:00
+++ b/sql/sql_table.cc	2007-07-19 19:43:11 -06:00
@@ -1565,7 +1565,7 @@ int mysql_rm_table_part2(THD *thd, TABLE
       table->db_type= share->db_type();
 
     /* Disable drop of enabled log tables */
-    if (share && share->log_table &&
+    if (share && (share->table_category == TABLE_CATEGORY_PERFORMANCE) &&
         check_if_log_table(table->db_length, table->db,
                            table->table_name_length, table->table_name, 1))
     {
@@ -4067,9 +4067,11 @@ static bool mysql_admin_table(THD* thd, 
                              table->table_name, 1) &&
           lock_type >= TL_READ_NO_INSERT)
       {
+        DBUG_ASSERT((thd->options & OPTION_INTERNAL_PRIVILEGE) == 0);
+        thd->options|= OPTION_INTERNAL_PRIVILEGE;
+
         disable_logs= 1;
         logger.lock();
-        logger.tmp_close_log_tables(thd);
       }
 
       open_and_lock_tables(thd, table);
@@ -4141,8 +4143,7 @@ static bool mysql_admin_table(THD* thd, 
     }
 
     /* Close all instances of the table to allow repair to rename files */
-    if (lock_type == TL_WRITE && table->table->s->version &&
-        !table->table->s->log_table)
+    if (lock_type == TL_WRITE && table->table->s->version)
     {
       pthread_mutex_lock(&LOCK_open);
       const char *old_message=thd->enter_cond(&COND_refresh, &LOCK_open,
@@ -4366,10 +4367,9 @@ send_result_message:
     }
     if (table->table)
     {
-      /* in the below check we do not refresh the log tables */
       if (fatal_error)
         table->table->s->version=0;               // Force close of table
-      else if (open_for_modify && !table->table->s->log_table)
+      else if (open_for_modify)
       {
         if (table->table->s->tmp_table)
           table->table->file->info(HA_STATUS_CONST);
@@ -4394,9 +4394,8 @@ send_result_message:
   send_eof(thd);
   if (disable_logs)
   {
-    if (logger.reopen_log_tables())
-      my_error(ER_CANT_ACTIVATE_LOG, MYF(0));
     logger.unlock();
+    thd->options&= ~OPTION_INTERNAL_PRIVILEGE;
   }
   DBUG_RETURN(FALSE);
 
@@ -4406,9 +4405,8 @@ send_result_message:
   /* enable logging back if needed */
   if (disable_logs)
   {
-    if (logger.reopen_log_tables())
-      my_error(ER_CANT_ACTIVATE_LOG, MYF(0));
     logger.unlock();
+    thd->options&= ~OPTION_INTERNAL_PRIVILEGE;
   }
   if (table)
     table->table=0;
@@ -5658,7 +5656,7 @@ err:
   Alter table
 
   SYNOPSIS
-    mysql_alter_table()
+    mysql_alter_table_impl()
       thd              Thread handle
       new_db           If there is a RENAME clause
       new_name         If there is a RENAME clause
@@ -5696,7 +5694,7 @@ err:
     TRUE   Error
 */
 
-bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
+bool mysql_alter_table_impl(THD *thd,char *new_db, char *new_name,
                        HA_CREATE_INFO *create_info,
                        TABLE_LIST *table_list,
                        Alter_info *alter_info,
@@ -5733,48 +5731,6 @@ bool mysql_alter_table(THD *thd,char *ne
   LINT_INIT(index_drop_buffer);
 
   /*
-    Check if we attempt to alter mysql.slow_log or
-    mysql.general_log table and return an error if
-    it is the case.
-    TODO: this design is obsolete and will be removed.
-  */
-  if (table_list && table_list->db && table_list->table_name)
-  {
-    int table_kind= 0;
-
-    table_kind= check_if_log_table(table_list->db_length, table_list->db,
-                                   table_list->table_name_length,
-                                   table_list->table_name, 0);
-
-    if (table_kind)
-    {
-      /* Disable alter of enabled log tables */
-      if (logger.is_log_table_enabled(table_kind))
-      {
-        my_error(ER_BAD_LOG_STATEMENT, MYF(0), "ALTER");
-        DBUG_RETURN(TRUE);
-      }
-
-      /* Disable alter of log tables to unsupported engine */
-      if ((create_info->used_fields & HA_CREATE_USED_ENGINE) &&
-          (!create_info->db_type || /* unknown engine */
-           !(create_info->db_type->flags & HTON_SUPPORT_LOG_TABLES)))
-      {
-        my_error(ER_UNSUPORTED_LOG_ENGINE, MYF(0));
-        DBUG_RETURN(TRUE);
-      }
-
-#ifdef WITH_PARTITION_STORAGE_ENGINE
-      if (alter_info->flags & ALTER_PARTITION)
-      {
-	my_error(ER_WRONG_USAGE, MYF(0), "PARTITION", "log table");
-        DBUG_RETURN(TRUE);
-      }
-#endif
-    }
-  }
-
-  /*
     Assign variables table_name, new_name, db, new_db, path, reg_path
     to simplify further comparisions: we want to see if it's a RENAME
     later just by comparing the pointers, avoiding the need for strcmp.
@@ -6759,7 +6715,73 @@ err_with_placeholders:
   VOID(pthread_mutex_unlock(&LOCK_open));
   DBUG_RETURN(TRUE);
 }
-/* mysql_alter_table */
+
+
+bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
+                       HA_CREATE_INFO *create_info,
+                       TABLE_LIST *table_list,
+                       Alter_info *alter_info,
+                       uint order_num, ORDER *order, bool ignore)
+{
+  bool result;
+
+  DBUG_ENTER("mysql_alter_table");
+  DBUG_ASSERT((thd->options & OPTION_INTERNAL_PRIVILEGE) == 0);
+
+  /*
+    Check if we attempt to alter mysql.slow_log or
+    mysql.general_log table and return an error if
+    it is the case.
+    TODO: this design is obsolete and will be removed.
+  */
+  if (table_list && table_list->db && table_list->table_name)
+  {
+    int table_kind= 0;
+
+    table_kind= check_if_log_table(table_list->db_length, table_list->db,
+                                   table_list->table_name_length,
+                                   table_list->table_name, 0);
+
+    if (table_kind)
+    {
+      /* Disable alter of enabled log tables */
+      if (logger.is_log_table_enabled(table_kind))
+      {
+        my_error(ER_BAD_LOG_STATEMENT, MYF(0), "ALTER");
+        DBUG_RETURN(TRUE);
+      }
+
+      /* Disable alter of log tables to unsupported engine */
+      if ((create_info->used_fields & HA_CREATE_USED_ENGINE) &&
+          (!create_info->db_type || /* unknown engine */
+           !(create_info->db_type->flags & HTON_SUPPORT_LOG_TABLES)))
+      {
+        my_error(ER_UNSUPORTED_LOG_ENGINE, MYF(0));
+        DBUG_RETURN(TRUE);
+      }
+
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+      if (alter_info->flags & ALTER_PARTITION)
+      {
+        my_error(ER_WRONG_USAGE, MYF(0), "PARTITION", "log table");
+        DBUG_RETURN(TRUE);
+      }
+#endif
+
+      DBUG_ASSERT((thd->options & OPTION_INTERNAL_PRIVILEGE) == 0);
+      thd->options|= OPTION_INTERNAL_PRIVILEGE;
+    }
+  }
+
+  result= mysql_alter_table_impl(thd, new_db, new_name, create_info,
+                                 table_list, alter_info, order_num,
+                                 order, ignore);
+
+  thd->options&= ~OPTION_INTERNAL_PRIVILEGE;
+
+  DBUG_RETURN(result);
+}
+
 
 static int
 copy_data_between_tables(TABLE *from,TABLE *to,
diff -Nrup a/sql/table.cc b/sql/table.cc
--- a/sql/table.cc	2007-06-25 03:22:22 -06:00
+++ b/sql/table.cc	2007-07-19 19:43:11 -06:00
@@ -21,6 +21,18 @@
 #include <m_ctype.h>
 #include "md5.h"
 
+/* INFORMATION_SCHEMA name */
+LEX_STRING INFORMATION_SCHEMA_NAME= {C_STRING_WITH_LEN("information_schema")};
+
+/* MYSQL_SCHEMA name */
+LEX_STRING MYSQL_SCHEMA_NAME= {C_STRING_WITH_LEN("mysql")};
+
+/* GENERAL_LOG name */
+LEX_STRING GENERAL_LOG_NAME= {C_STRING_WITH_LEN("general_log")};
+
+/* SLOW_LOG name */
+LEX_STRING SLOW_LOG_NAME= {C_STRING_WITH_LEN("slow_log")};
+
 	/* Functions defined in this file */
 
 void open_table_error(TABLE_SHARE *share, int error, int db_errno,
@@ -31,6 +43,7 @@ static void fix_type_pointers(const char
 			      uint types, char **names);
 static uint find_field(Field **fields, uchar *record, uint start, uint length);
 
+inline bool is_system_table_name(const char *name, uint length);
 
 /* Get column name from column hash */
 
@@ -73,6 +86,50 @@ char *fn_rext(char *name)
 }
 
 
+TABLE_CATEGORY get_table_category(const LEX_STRING *db, const LEX_STRING *name)
+{
+  DBUG_ASSERT(db != NULL);
+  DBUG_ASSERT(name != NULL);
+
+  if ((db->length == INFORMATION_SCHEMA_NAME.length) &&
+      (my_strcasecmp(system_charset_info,
+                    INFORMATION_SCHEMA_NAME.str,
+                    db->str) == 0))
+  {
+    return TABLE_CATEGORY_INFORMATION;
+  }
+
+  if ((db->length == MYSQL_SCHEMA_NAME.length) &&
+      (my_strcasecmp(system_charset_info,
+                    MYSQL_SCHEMA_NAME.str,
+                    db->str) == 0))
+  {
+    if (is_system_table_name(name->str, name->length))
+    {
+      return TABLE_CATEGORY_SYSTEM;
+    }
+
+    if ((name->length == GENERAL_LOG_NAME.length) &&
+        (my_strcasecmp(system_charset_info,
+                      GENERAL_LOG_NAME.str,
+                      name->str) == 0))
+    {
+      return TABLE_CATEGORY_PERFORMANCE;
+    }
+
+    if ((name->length == SLOW_LOG_NAME.length) &&
+        (my_strcasecmp(system_charset_info,
+                      SLOW_LOG_NAME.str,
+                      name->str) == 0))
+    {
+      return TABLE_CATEGORY_PERFORMANCE;
+    }
+  }
+
+  return TABLE_CATEGORY_USER;
+}
+
+
 /*
   Allocate a setup TABLE_SHARE structure
 
@@ -177,7 +234,8 @@ void init_tmp_table_share(TABLE_SHARE *s
 
   bzero((char*) share, sizeof(*share));
   init_sql_alloc(&share->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0);
-  share->tmp_table=  	         INTERNAL_TMP_TABLE;
+  share->table_category=         TABLE_CATEGORY_TEMPORARY;
+  share->tmp_table=              INTERNAL_TMP_TABLE;
   share->db.str=                 (char*) key;
   share->db.length=		 strlen(key);
   share->table_cache_key.str=    (char*) key;
@@ -425,27 +483,11 @@ int open_table_def(THD *thd, TABLE_SHARE
     error= open_binary_frm(thd, share, head, file);
     *root_ptr= old_root;
 
-    if (share->db.length == 5 && !(lower_case_table_names ?
-        my_strcasecmp(system_charset_info, share->db.str, "mysql") :
-        strcmp(share->db.str, "mysql")))
-    {
-      /*
-        We can't mark all tables in 'mysql' database as system since we don't
-        allow to lock such tables for writing with any other tables (even with
-        other system tables) and some privilege tables need this.
-      */
-      share->system_table= is_system_table_name(share->table_name.str,
-                                                share->table_name.length);
-      if (!share->system_table)
-      {
-        share->log_table= check_if_log_table(share->db.length, share->db.str,
-                                             share->table_name.length,
-                                             share->table_name.str, 0);
-      }
-    }
     error_given= 1;
   }
 
+  share->table_category= get_table_category(& share->db, & share->table_name);
+
   if (!error)
     thd->status_var.opened_shares++;
 
@@ -647,7 +689,7 @@ static int open_binary_frm(THD *thd, TAB
 
   share->reclength = uint2korr((head+16));
   if (*(head+26) == 1)
-    share->system= 1;				/* one-record-database */
+    share->one_record_table= 1;                     /* one-record-database */
 #ifdef HAVE_CRYPTED_FRM
   else if (*(head+26) == 2)
   {
diff -Nrup a/sql/table.h b/sql/table.h
--- a/sql/table.h	2007-06-05 13:19:57 -06:00
+++ b/sql/table.h	2007-07-19 19:43:11 -06:00
@@ -108,6 +108,100 @@ class Field_timestamp;
 class Field_blob;
 class Table_triggers_list;
 
+
+/**
+  Category of table found in the table share.
+*/
+enum enum_table_category
+{
+  /**
+    Unknown value.
+  */
+  TABLE_UNKNOWN_CATEGORY=0,
+
+  /**
+    Temporary table.
+    The table is visible only in the session.
+    Therefore,
+    - LOCK TABLE <t> FOR READ/WRITE
+    - FLUSH TABLES WITH READ LOCK
+    - SET GLOBAL READ_ONLY = ON
+    do not apply to this table.
+    Temporary tables are not part of the table cache.
+  */
+  TABLE_CATEGORY_TEMPORARY=1,
+
+  /**
+    User table.
+    These tables do honor:
+    - LOCK TABLE <t> FOR READ/WRITE
+    - FLUSH TABLES WITH READ LOCK
+    - SET GLOBAL READ_ONLY = ON
+    User tables are cached in the table cache.
+  */
+  TABLE_CATEGORY_USER=2,
+
+  /**
+    System table, maintained by the server.
+    These tables do honor:
+    - LOCK TABLE <t> FOR READ/WRITE
+    - FLUSH TABLES WITH READ LOCK
+    - SET GLOBAL READ_ONLY = ON
+    Typically, writes to system tables are performed by
+    the server implementation, not explicitly be a user.
+    System tables are cached in the table cache.
+  */
+  TABLE_CATEGORY_SYSTEM=3,
+
+  /**
+    Information schema tables.
+    These tables are an interface provided by the system
+    to inspect the system metadata.
+    These tables do *not* honor:
+    - LOCK TABLE <t> FOR READ/WRITE
+    - FLUSH TABLES WITH READ LOCK
+    - SET GLOBAL READ_ONLY = ON
+    as there is no point in locking explicitely
+    an INFORMATION_SCHEMA table.
+    Nothing is directly written to information schema tables.
+    Note that this value is not used currently,
+    since information schema tables are not shared,
+    but implemented as session specific temporary tables.
+  */
+  /*
+    TODO: Fixing the performance issues of I_S will lead
+    to I_S tables in the table cache, which should use
+    this table type.
+  */
+  TABLE_CATEGORY_INFORMATION=4,
+
+  /**
+    Performance schema tables.
+    These tables are an interface provided by the system
+    to inspect the system performance data.
+    These tables do *not* honor:
+    - LOCK TABLE <t> FOR READ/WRITE
+    - FLUSH TABLES WITH READ LOCK
+    - SET GLOBAL READ_ONLY = ON
+    as there is no point in locking explicitely
+    a PERFORMANCE_SCHEMA table.
+    An example of PERFORMANCE_SCHEMA tables are:
+    - mysql.slow_log
+    - mysql.general_log,
+    which *are* updated even when there is either
+    a GLOBAL READ LOCK or a GLOBAL READ_ONLY in effect.
+    User queries do not write directly to these tables
+    (there are exceptions for log tables).
+    The server implementation perform writes.
+    Performance tables are cached in the table cache.
+  */
+  TABLE_CATEGORY_PERFORMANCE=5
+};
+typedef enum enum_table_category TABLE_CATEGORY;
+
+TABLE_CATEGORY get_table_category(const LEX_STRING *db,
+                                  const LEX_STRING *name);
+
 /*
   This structure is shared between different table objects. There is one
   instance of table share per one table in the database.
@@ -116,6 +210,9 @@ class Table_triggers_list;
 typedef struct st_table_share
 {
   st_table_share() {}                    /* Remove gcc warning */
+
+  TABLE_CATEGORY table_category;
+
   /* hash of field names (contains pointers to elements of field array) */
   HASH	name_hash;			/* hash of field names */
   MEM_ROOT mem_root;
@@ -209,7 +306,10 @@ typedef struct st_table_share
   uint column_bitmap_size;
   uchar frm_version;
   bool null_field_first;
-  bool system;                          /* Set if system table (one record) */
+
+  /** Set if system table (one record) */
+  bool one_record_table;
+
   bool crypted;                         /* If .frm file is crypted */
   bool db_low_byte_first;		/* Portable row format */
   bool crashed;
@@ -227,18 +327,6 @@ typedef struct st_table_share
   */
   int cached_row_logging_check;
 
-  /*
-    TRUE if this is a system table like 'mysql.proc', which we want to be
-    able to open and lock even when we already have some tables open and
-    locked. To avoid deadlocks we have to put certain restrictions on
-    locking of this table for writing. FALSE - otherwise.
-  */
-  bool system_table;
-  /*
-    This flag is set for the log tables. Used during FLUSH instances to skip
-    log tables, while closing tables (since logs must be always available)
-  */
-  bool log_table;
 #ifdef WITH_PARTITION_STORAGE_ENGINE
   bool auto_partitioned;
   const char *partition_info;
@@ -302,6 +390,16 @@ typedef struct st_table_share
     set_table_cache_key(key_buff, key_length);
   }
 
+  inline bool honor_global_locks()
+  {
+    return ((table_category == TABLE_CATEGORY_USER)
+            || (table_category == TABLE_CATEGORY_SYSTEM));
+  }
+
+  inline bool require_write_privileges()
+  {
+    return (table_category == TABLE_CATEGORY_PERFORMANCE);
+  }
 } TABLE_SHARE;
 
 
@@ -459,7 +557,6 @@ struct st_table {
     not rely on that.
   */
   my_bool open_placeholder;
-  my_bool locked_by_logger;
   my_bool no_replicate;
   my_bool locked_by_name;
   my_bool fulltext_searched;
diff -Nrup a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc
--- a/storage/csv/ha_tina.cc	2007-06-15 00:27:08 -06:00
+++ b/storage/csv/ha_tina.cc	2007-07-19 19:43:11 -06:00
@@ -785,18 +785,6 @@ void ha_tina::update_status()
 }
 
 
-bool ha_tina::check_if_locking_is_allowed(uint sql_command,
-                                          ulong type, TABLE *table,
-                                          uint count, uint current,
-                                          uint *system_count,
-                                          bool called_by_privileged_thread)
-{
-  if (!called_by_privileged_thread)
-    return check_if_log_table_locking_is_allowed(sql_command, type, table);
-
-  return TRUE;
-}
-
 /*
   Open a database file. Keep in mind that tables are caches, so
   this will not be called for every request. Any sort of positions
diff -Nrup a/storage/csv/ha_tina.h b/storage/csv/ha_tina.h
--- a/storage/csv/ha_tina.h	2007-06-12 14:12:35 -06:00
+++ b/storage/csv/ha_tina.h	2007-07-19 19:43:11 -06:00
@@ -127,11 +127,6 @@ public:
   */
   ha_rows estimate_rows_upper_bound() { return HA_POS_ERROR; }
 
-  virtual bool check_if_locking_is_allowed(uint sql_command,
-                                           ulong type, TABLE *table,
-                                           uint count, uint current,
-                                           uint *system_count,
-                                           bool called_by_logger_thread);
   int open(const char *name, int mode, uint open_options);
   int close(void);
   int write_row(uchar * buf);
diff -Nrup a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc
--- a/storage/myisam/ha_myisam.cc	2007-06-18 04:09:22 -06:00
+++ b/storage/myisam/ha_myisam.cc	2007-07-19 19:43:11 -06:00
@@ -607,41 +607,7 @@ err:
 #endif /* HAVE_REPLICATION */
 
 
-bool ha_myisam::check_if_locking_is_allowed(uint sql_command,
-                                            ulong type, TABLE *table,
-                                            uint count, uint current,
-                                            uint *system_count,
-                                            bool called_by_privileged_thread)
-{
-  /*
-    To be able to open and lock for reading system tables like 'mysql.proc',
-    when we already have some tables opened and locked, and avoid deadlocks
-    we have to disallow write-locking of these tables with any other tables.
-  */
-  if (table->s->system_table &&
-      table->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE)
-    (*system_count)++;
-
-  /* 'current' is an index, that's why '<=' below. */
-  if (*system_count > 0 && *system_count <= current)
-  {
-    my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0));
-    return FALSE;
-  }
-
-  /*
-    Deny locking of the log tables, which is incompatible with
-    concurrent insert. Unless called from a logger THD (general_log_thd
-    or slow_log_thd) or by a privileged thread.
-  */
-  if (!called_by_privileged_thread)
-    return check_if_log_table_locking_is_allowed(sql_command, type, table);
-
-  return TRUE;
-}
-
-	/* Name is here without an extension */
-
+/* Name is here without an extension */
 int ha_myisam::open(const char *name, int mode, uint test_if_locked)
 {
   MI_KEYDEF *keyinfo;
diff -Nrup a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h
--- a/storage/myisam/ha_myisam.h	2007-05-10 03:59:32 -06:00
+++ b/storage/myisam/ha_myisam.h	2007-07-19 19:43:11 -06:00
@@ -60,11 +60,6 @@ class ha_myisam: public handler
   uint max_supported_key_part_length() const { return MI_MAX_KEY_LENGTH; }
   uint checksum() const;
 
-  virtual bool check_if_locking_is_allowed(uint sql_command,
-                                           ulong type, TABLE *table,
-                                           uint count, uint current,
-                                           uint *system_count,
-                                           bool called_by_logger_thread);
   int open(const char *name, int mode, uint test_if_locked);
   int close(void);
   int write_row(uchar * buf);
Thread
bk commit into 5.1 tree (malff:1.2516) BUG#25422marc.alff20 Jul
  • Re: bk commit into 5.1 tree (malff:1.2516) BUG#25422Konstantin Osipov25 Jul