MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:konstantin Date:April 3 2007 10:34am
Subject:bk commit into 5.1 tree (kostja:1.2551)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of kostja. When kostja 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-04-03 14:34:37+04:00, kostja@stripped +21 -0
  Merge bk-internal.mysql.com:/home/bk/mysql-5.1
  into  bodhi.local:/opt/local/work/mysql-5.1-runtime
  MERGE: 1.2473.45.13

  mysql-test/r/events.result@stripped, 2007-04-03 14:34:31+04:00, kostja@stripped +3 -6
    Manual merge.
    MERGE: 1.46.1.3

  mysql-test/r/events_bugs.result@stripped, 2007-04-03 14:29:58+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.26.1.1

  mysql-test/r/ps.result@stripped, 2007-04-03 14:29:58+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.104.1.1

  mysql-test/t/events.test@stripped, 2007-04-03 14:29:58+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.43.1.2

  sql/event_data_objects.cc@stripped, 2007-04-03 14:29:58+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.89.1.2

  sql/event_data_objects.h@stripped, 2007-04-03 14:29:58+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.17.1.2

  sql/event_db_repository.cc@stripped, 2007-04-03 14:34:31+04:00, kostja@stripped +0 -0
    Manual merge.
    MERGE: 1.24.1.1

  sql/event_db_repository.h@stripped, 2007-04-03 14:29:58+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.12.1.2

  sql/event_queue.cc@stripped, 2007-04-03 14:29:58+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.27.1.1

  sql/events.cc@stripped, 2007-04-03 14:29:58+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.71.1.2

  sql/ha_ndbcluster.cc@stripped, 2007-04-03 14:29:58+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.415.2.1

  sql/item_func.cc@stripped, 2007-04-03 14:29:59+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.367.1.1

  sql/mysql_priv.h@stripped, 2007-04-03 14:29:59+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.490.1.2

  sql/mysqld.cc@stripped, 2007-04-03 14:29:59+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.622.4.2

  sql/set_var.cc@stripped, 2007-04-03 14:30:00+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.222.1.1

  sql/share/errmsg.txt@stripped, 2007-04-03 14:30:04+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.149.1.1

  sql/sql_parse.cc@stripped, 2007-04-03 14:34:31+04:00, kostja@stripped +1 -1
    Manual merge.
    MERGE: 1.648.1.2

  sql/sql_servers.cc@stripped, 2007-04-03 14:30:00+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.8.1.1

  sql/sql_view.cc@stripped, 2007-04-03 14:30:00+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.124.1.1

  sql/sql_yacc.yy@stripped, 2007-04-03 14:30:03+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.554.2.2

  sql/table.h@stripped, 2007-04-03 14:30:03+04:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.163.1.3

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	kostja
# Host:	bodhi.local
# Root:	/opt/local/work/mysql-5.1-runtime/RESYNC

--- 1.492/sql/mysql_priv.h	2007-03-28 18:25:47 +04:00
+++ 1.493/sql/mysql_priv.h	2007-04-03 14:29:59 +04:00
@@ -842,7 +842,7 @@
 bool alloc_query(THD *thd, const char *packet, uint packet_length);
 void mysql_init_select(LEX *lex);
 void mysql_reset_thd_for_next_command(THD *thd);
-void mysql_init_query(THD *thd, uchar *buf, uint length);
+void mysql_init_query(THD *thd, const char *buf, uint length);
 bool mysql_new_select(LEX *lex, bool move_down);
 void create_select_for_variable(const char *var_name);
 void mysql_init_multi_delete(LEX *lex);
@@ -1565,8 +1565,10 @@
 /* strfunc.cc */
 ulonglong find_set(TYPELIB *lib, const char *x, uint length, CHARSET_INFO *cs,
 		   char **err_pos, uint *err_len, bool *set_warning);
-uint find_type(TYPELIB *lib, const char *find, uint length, bool part_match);
-uint find_type2(TYPELIB *lib, const char *find, uint length, CHARSET_INFO *cs);
+uint find_type(const TYPELIB *lib, const char *find, uint length,
+               bool part_match);
+uint find_type2(const TYPELIB *lib, const char *find, uint length,
+                CHARSET_INFO *cs);
 void unhex_type2(TYPELIB *lib);
 uint check_word(TYPELIB *lib, const char *val, const char *end,
 		const char **end_of_word);

--- 1.625/sql/mysqld.cc	2007-03-31 14:38:12 +04:00
+++ 1.626/sql/mysqld.cc	2007-04-03 14:29:59 +04:00
@@ -6732,12 +6732,20 @@
   return 0;
 }
 
-/* Functions relying on SSL */
+/*
+   Functions relying on SSL 
+   Note: In the show_ssl_* functions, we need to check if we have a
+         valid vio-object since this isn't always true, specifically
+         when session_status or global_status is requested from
+         inside an Event.
+ */
 static int show_ssl_get_version(THD *thd, SHOW_VAR *var, char *buff)
 {
   var->type= SHOW_CHAR;
-  var->value= const_cast<char*>(thd->net.vio->ssl_arg ?
-        SSL_get_version((SSL*) thd->net.vio->ssl_arg) : "");
+  if( thd->vio_ok() && thd->net.vio->ssl_arg )
+    var->value= const_cast<char*>(SSL_get_version((SSL*) thd->net.vio->ssl_arg));
+  else
+    var->value= (char *)"";
   return 0;
 }
 
@@ -6745,9 +6753,10 @@
 {
   var->type= SHOW_LONG;
   var->value= buff;
-  *((long *)buff)= (long)thd->net.vio->ssl_arg ?
-                         SSL_session_reused((SSL*) thd->net.vio->ssl_arg) :
-                         0;
+  if( thd->vio_ok() && thd->net.vio->ssl_arg )
+    *((long *)buff)= (long)SSL_session_reused((SSL*) thd->net.vio->ssl_arg);
+  else
+    *((long *)buff)= 0;
   return 0;
 }
 
@@ -6755,9 +6764,10 @@
 {
   var->type= SHOW_LONG;
   var->value= buff;
-  *((long *)buff)= (long)thd->net.vio->ssl_arg ?
-                         SSL_get_default_timeout((SSL*)thd->net.vio->ssl_arg) :
-                         0;
+  if( thd->vio_ok() && thd->net.vio->ssl_arg )
+    *((long *)buff)= (long)SSL_get_default_timeout((SSL*)thd->net.vio->ssl_arg);
+  else
+    *((long *)buff)= 0;
   return 0;
 }
 
@@ -6765,9 +6775,10 @@
 {
   var->type= SHOW_LONG;
   var->value= buff;
-  *((long *)buff)= (long)thd->net.vio->ssl_arg ?
-                         SSL_get_verify_mode((SSL*)thd->net.vio->ssl_arg) :
-                         0;
+  if( thd->net.vio && thd->net.vio->ssl_arg )
+    *((long *)buff)= (long)SSL_get_verify_mode((SSL*)thd->net.vio->ssl_arg);
+  else
+    *((long *)buff)= 0;
   return 0;
 }
 
@@ -6775,17 +6786,20 @@
 {
   var->type= SHOW_LONG;
   var->value= buff;
-  *((long *)buff)= (long)thd->net.vio->ssl_arg ?
-                         SSL_get_verify_depth((SSL*)thd->net.vio->ssl_arg) :
-                         0;
+  if( thd->vio_ok() && thd->net.vio->ssl_arg )
+    *((long *)buff)= (long)SSL_get_verify_depth((SSL*)thd->net.vio->ssl_arg);
+  else
+    *((long *)buff)= 0;
   return 0;
 }
 
 static int show_ssl_get_cipher(THD *thd, SHOW_VAR *var, char *buff)
 {
   var->type= SHOW_CHAR;
-  var->value= const_cast<char*>(thd->net.vio->ssl_arg ?
-              SSL_get_cipher((SSL*) thd->net.vio->ssl_arg) : "");
+  if( thd->vio_ok() && thd->net.vio->ssl_arg )
+    var->value= const_cast<char*>(SSL_get_cipher((SSL*) thd->net.vio->ssl_arg));
+  else
+    var->value= (char *)"";
   return 0;
 }
 
@@ -6793,7 +6807,7 @@
 {
   var->type= SHOW_CHAR;
   var->value= buff;
-  if (thd->net.vio->ssl_arg)
+  if (thd->vio_ok() && thd->net.vio->ssl_arg)
   {
     int i;
     const char *p;

--- 1.649/sql/sql_parse.cc	2007-03-27 21:09:51 +04:00
+++ 1.650/sql/sql_parse.cc	2007-04-03 14:34:31 +04:00
@@ -2595,6 +2595,36 @@
     break;
   }
   case SQLCOM_REPLACE:
+#ifndef DBUG_OFF
+    if (mysql_bin_log.is_open())
+    {
+      /*
+        Generate an incident log event before writing the real event
+        to the binary log.  We put this event is before the statement
+        since that makes it simpler to check that the statement was
+        not executed on the slave (since incidents usually stop the
+        slave).
+
+        Observe that any row events that are generated will be
+        generated before.
+
+        This is only for testing purposes and will not be present in a
+        release build.
+      */
+
+      Incident incident= INCIDENT_NONE;
+      DBUG_PRINT("debug", ("Just before generate_incident()"));
+      DBUG_EXECUTE_IF("incident_database_resync_on_replace",
+                      incident= INCIDENT_LOST_EVENTS;);
+      if (incident)
+      {
+        Incident_log_event ev(thd, incident);
+        mysql_bin_log.write(&ev);
+        mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
+      }
+      DBUG_PRINT("debug", ("Just after generate_incident()"));
+    }
+#endif
   case SQLCOM_INSERT:
   {
     DBUG_ASSERT(first_table == all_tables && first_table != 0);
@@ -3923,7 +3953,6 @@
 	    if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0))
 	      goto error;
 
-	    /* Does NOT write to binlog */
 	    if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
 	    {
 	      send_ok(thd);
@@ -4274,6 +4303,10 @@
     int error;
     LEX *lex= thd->lex;
     DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER"));
+
+    if (check_global_access(thd, SUPER_ACL))
+      break;
+
     if ((error= create_server(thd, &lex->server_options)))
     {
       DBUG_PRINT("info", ("problem creating server <%s>",
@@ -4289,6 +4322,10 @@
     int error;
     LEX *lex= thd->lex;
     DBUG_PRINT("info", ("case SQLCOM_ALTER_SERVER"));
+
+    if (check_global_access(thd, SUPER_ACL))
+      break;
+
     if ((error= alter_server(thd, &lex->server_options)))
     {
       DBUG_PRINT("info", ("problem altering server <%s>",
@@ -4304,9 +4341,13 @@
     int err_code;
     LEX *lex= thd->lex;
     DBUG_PRINT("info", ("case SQLCOM_DROP_SERVER"));
+
+    if (check_global_access(thd, SUPER_ACL))
+      break;
+
     if ((err_code= drop_server(thd, &lex->server_options)))
     {
-      if (! lex->drop_if_exists && err_code == ER_FOREIGN_SERVER_EXISTS)
+      if (! lex->drop_if_exists && err_code == ER_FOREIGN_SERVER_DOESNT_EXIST)
       {
         DBUG_PRINT("info", ("problem dropping server %s",
                             lex->server_options.server_name));
@@ -5182,6 +5223,7 @@
   lex->query_tables_last= &lex->query_tables;
 }
 
+
 /*
   When you modify mysql_parse(), you may need to mofify
   mysql_test_parse_for_slave() in this same file.
@@ -5194,6 +5236,7 @@
   DBUG_EXECUTE_IF("parser_debug", turn_parser_debug_on(););
 
   mysql_init_query(thd, inBuf, length);
+
   if (query_cache_send_result_to_client(thd, inBuf, length) <= 0)
   {
     LEX *lex= thd->lex;

--- 1.558/sql/sql_yacc.yy	2007-03-31 14:38:13 +04:00
+++ 1.559/sql/sql_yacc.yy	2007-04-03 14:30:03 +04:00
@@ -1853,7 +1853,7 @@
             */
             if (lex->sphead)
             {
-              my_error(ER_EVENT_RECURSIVITY_FORBIDDEN, MYF(0));
+              my_error(ER_EVENT_RECURSION_FORBIDDEN, MYF(0));
               MYSQL_YYABORT;
             }
               
@@ -2701,7 +2701,7 @@
               else
                 i->m_query.length= lex->tok_end - sp->m_tmp_query;
               i->m_query.str= strmake_root(YYTHD->mem_root,
-                                           (char *)sp->m_tmp_query,
+                                           sp->m_tmp_query,
                                            i->m_query.length);
               sp->add_instr(i);
             }
@@ -9305,7 +9305,7 @@
             my_error(ER_VIEW_SELECT_VARIABLE, MYF(0));
             MYSQL_YYABORT;
           }
-          item= new Item_param((uint) (lex->tok_start - (uchar *) thd->query));
+          item= new Item_param((uint) (lex->tok_start - thd->query));
           if (!($$= item) || lex->param_list.push_back(item))
           {
             my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
@@ -10142,7 +10142,7 @@
               if (!(qbuff.str= alloc_root(YYTHD->mem_root, qbuff.length + 5)))
                 MYSQL_YYABORT;
 
-              strmake(strmake(qbuff.str, "SET ", 4), (char *)sp->m_tmp_query,
+              strmake(strmake(qbuff.str, "SET ", 4), sp->m_tmp_query,
                       qbuff.length);
               qbuff.length+= 4;
               i->m_query= qbuff;
@@ -11361,18 +11361,16 @@
 	{
           THD *thd= YYTHD;
           LEX *lex= thd->lex;
-          char *stmt_beg= (lex->sphead ?
-                           (char *)lex->sphead->m_tmp_query :
-                           thd->query);
+          const char *stmt_beg= (lex->sphead ?
+                                 lex->sphead->m_tmp_query : thd->query);
 	  lex->create_view_select_start= $2 - stmt_beg;
 	}
 	| '(' remember_name select_paren ')' union_opt
 	{
           THD *thd= YYTHD;
           LEX *lex= thd->lex;
-          char *stmt_beg= (lex->sphead ?
-                           (char *)lex->sphead->m_tmp_query :
-                           thd->query);
+          const char *stmt_beg= (lex->sphead ?
+                                 lex->sphead->m_tmp_query : thd->query);
 	  lex->create_view_select_start= $2 - stmt_beg;
 	}
 	;

--- 1.164/sql/table.h	2007-03-27 21:09:52 +04:00
+++ 1.165/sql/table.h	2007-04-03 14:30:03 +04:00
@@ -58,7 +58,7 @@
 
 enum tmp_table_type
 {
-  NO_TMP_TABLE, TMP_TABLE, TRANSACTIONAL_TMP_TABLE,
+  NO_TMP_TABLE, NON_TRANSACTIONAL_TMP_TABLE, TRANSACTIONAL_TMP_TABLE,
   INTERNAL_TMP_TABLE, SYSTEM_TMP_TABLE
 };
 
@@ -439,6 +439,11 @@
   my_bool no_cache;
   /* To signal that we should reset query_id for tables and cols */
   my_bool clear_query_id;
+  /*
+    To indicate that a non-null value of the auto_increment field
+    was provided by the user or retrieved from the current record.
+    Used only in the MODE_NO_AUTO_VALUE_ON_ZERO mode.
+  */
   my_bool auto_increment_field_not_null;
   my_bool insert_or_update;             /* Can be used by the handler */
   my_bool alias_name_used;		/* true if table_name is alias */

--- 1.49/mysql-test/r/events.result	2007-03-29 19:10:42 +04:00
+++ 1.50/mysql-test/r/events.result	2007-04-03 14:34:31 +04:00
@@ -73,7 +73,7 @@
 create table test_nested(a int);
 create event e_43 on schedule every 1 second do set @a = 5;
 alter event e_43 do alter event e_43 do set @a = 4;
-ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present
+ERROR HY000: Recursion of EVENT DDL statements is forbidden when body is present
 alter event e_43 do
 begin
 alter event e_43 on schedule every 5 minute;
@@ -229,10 +229,10 @@
 events_test	intact_check	root@localhost	SYSTEM	RECURRING	NULL	10	#	#	NULL	ENABLED	1
 ALTER TABLE mysql.event ADD dummy INT FIRST;
 SHOW EVENTS;
-ERROR HY000: Column count of mysql.event is wrong. Expected 18, found 19. Table probably corrupted
+ERROR HY000: Column count of mysql.event is wrong. Expected 18, found 19. The table is probably corrupted
 ALTER TABLE mysql.event DROP dummy, ADD dummy2 VARCHAR(64) FIRST;
 SHOW EVENTS;
-ERROR HY000: Column count of mysql.event is wrong. Expected 18, found 19. Table probably corrupted
+ERROR HY000: Column count of mysql.event is wrong. Expected 18, found 19. The table is probably corrupted
 ALTER TABLE mysql.event DROP dummy2;
 SHOW EVENTS;
 Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status	Originator
@@ -241,7 +241,7 @@
 INSERT INTO event_like SELECT * FROM mysql.event;
 ALTER TABLE mysql.event MODIFY db char(64) character set cp1251 default '';
 SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
-ERROR HY000: Cannot load from mysql.event. Table probably corrupted. See error log.
+ERROR HY000: Cannot load from mysql.event. The table is probably corrupted. Please see the error log for details
 ALTER TABLE mysql.event MODIFY db char(20) character set utf8 collate utf8_bin default '';
 SHOW CREATE TABLE mysql.event;
 Table	Create Table
@@ -267,7 +267,7 @@
   PRIMARY KEY (`db`,`name`)
 ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Events'
 SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
-ERROR HY000: Cannot load from mysql.event. Table probably corrupted. See error log.
+ERROR HY000: Cannot load from mysql.event. The table is probably corrupted. Please see the error log for details
 ALTER TABLE mysql.event MODIFY db char(64) character set utf8 collate utf8_bin default '';
 "This should work"
 SHOW EVENTS;
@@ -275,13 +275,13 @@
 events_test	intact_check	root@localhost	SYSTEM	RECURRING	NULL	10	#	#	NULL	ENABLED	1
 ALTER TABLE mysql.event MODIFY db char(64) character set cp1251 default '';
 SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
-ERROR HY000: Cannot load from mysql.event. Table probably corrupted. See error log.
+ERROR HY000: Cannot load from mysql.event. The table is probably corrupted. Please see the error log for details
 ALTER TABLE mysql.event MODIFY db varchar(64) character set utf8 collate utf8_bin default '';
 SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
-ERROR HY000: Cannot load from mysql.event. Table probably corrupted. See error log.
+ERROR HY000: Cannot load from mysql.event. The table is probably corrupted. Please see the error log for details
 ALTER TABLE mysql.event DROP comment, DROP starts;
 SELECT event_name FROM INFORMATION_SCHEMA.EVENTS;
-ERROR HY000: Column count of mysql.event is wrong. Expected 18, found 16. Table probably corrupted
+ERROR HY000: Column count of mysql.event is wrong. Expected 18, found 16. The table is probably corrupted
 DROP TABLE mysql.event;
 CREATE TABLE mysql.event like event_like;
 INSERT INTO  mysql.event SELECT * FROM event_like;
@@ -368,7 +368,7 @@
 drop event закачка21;
 create table t_16 (s1 int);
 create trigger t_16_bi before insert on t_16 for each row create event  e_16 on schedule every 1 second do set @a=5;
-ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present
+ERROR HY000: Recursion of EVENT DDL statements is forbidden when body is present
 drop table t_16;
 create event white_space
 on schedule every 10 hour

--- 1.27/mysql-test/r/events_bugs.result	2007-03-27 22:15:46 +04:00
+++ 1.28/mysql-test/r/events_bugs.result	2007-04-03 14:29:58 +04:00
@@ -30,7 +30,7 @@
 Warnings:
 Note	1584	Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. Event has not been created
 show events;
-Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
+Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status	Originator
 create event e_55 on schedule at 20200101000000 starts 10000101000000 do drop table t;
 ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'starts 10000101000000 do drop table t' at line 1
 create event e_55 on schedule at 20200101000000 ends 10000101000000 do drop table t;

--- 1.45/mysql-test/t/events.test	2007-03-29 17:25:52 +04:00
+++ 1.46/mysql-test/t/events.test	2007-04-03 14:29:58 +04:00
@@ -74,7 +74,7 @@
 #
 create table test_nested(a int);
 create event e_43 on schedule every 1 second do set @a = 5;
---error ER_EVENT_RECURSIVITY_FORBIDDEN
+--error ER_EVENT_RECURSION_FORBIDDEN
 alter event e_43 do alter event e_43 do set @a = 4;
 delimiter |;
 alter event e_43 do
@@ -351,7 +351,7 @@
 # Bug #16410  Events: CREATE EVENT is legal in a CREATE TRIGGER statement
 #
 create table t_16 (s1 int);
---error ER_EVENT_RECURSIVITY_FORBIDDEN
+--error ER_EVENT_RECURSION_FORBIDDEN
 create trigger t_16_bi before insert on t_16 for each row create event  e_16 on schedule every 1 second do set @a=5;
 drop table t_16;
 #

--- 1.73/sql/events.cc	2007-03-23 19:14:06 +03:00
+++ 1.74/sql/events.cc	2007-04-03 14:29:58 +04:00
@@ -324,7 +324,15 @@
     DBUG_RETURN(TRUE);
   }
 
+  /* 
+    Turn off row binlogging of this statement and use statement-based 
+    so that all supporting tables are updated for CREATE EVENT command.
+  */
+  if (thd->current_stmt_binlog_row_based)
+    thd->clear_current_stmt_binlog_row_based();
+
   pthread_mutex_lock(&LOCK_event_metadata);
+
   /* On error conditions my_error() is called so no need to handle here */
   if (!(ret= db_repository->create_event(thd, parse_data, if_not_exists)) &&
       !parse_data->do_not_create)
@@ -340,8 +348,16 @@
       DBUG_ASSERT(ret == OP_LOAD_ERROR);
       delete new_element;
     }
-    else
+    else /* Binlog the create event. */
+    {
       event_queue->create_event(thd, new_element);
+      if (mysql_bin_log.is_open() && (thd->query_length > 0))
+      {
+        thd->clear_error();
+        thd->binlog_query(THD::MYSQL_QUERY_TYPE,
+                          thd->query, thd->query_length, FALSE, FALSE);
+      }
+    }
   }
   pthread_mutex_unlock(&LOCK_event_metadata);
 
@@ -382,7 +398,15 @@
     DBUG_RETURN(TRUE);
   }
 
+  /* 
+    Turn off row binlogging of this statement and use statement-based 
+    so that all supporting tables are updated for UPDATE EVENT command.
+  */
+  if (thd->current_stmt_binlog_row_based)
+    thd->clear_current_stmt_binlog_row_based();
+
   pthread_mutex_lock(&LOCK_event_metadata);
+
   /* On error conditions my_error() is called so no need to handle here */
   if (!(ret= db_repository->update_event(thd, parse_data, new_dbname, new_name)))
   {
@@ -397,9 +421,17 @@
       DBUG_ASSERT(ret == OP_LOAD_ERROR);
       delete new_element;
     }
-    else
+    else /* Binlog the alter event. */
+    {
       event_queue->update_event(thd, parse_data->dbname, parse_data->name,
                                 new_element);
+      if (mysql_bin_log.is_open() && (thd->query_length > 0))
+      {
+        thd->clear_error();
+        thd->binlog_query(THD::MYSQL_QUERY_TYPE,
+                          thd->query, thd->query_length, FALSE, FALSE);
+      }
+    }
   }
   pthread_mutex_unlock(&LOCK_event_metadata);
 
@@ -434,10 +466,26 @@
     DBUG_RETURN(TRUE);
   }
 
+  /* 
+    Turn off row binlogging of this statement and use statement-based so 
+    that all supporting tables are updated for DROP EVENT command.
+  */
+  if (thd->current_stmt_binlog_row_based)
+    thd->clear_current_stmt_binlog_row_based();
+
   pthread_mutex_lock(&LOCK_event_metadata);
   /* On error conditions my_error() is called so no need to handle here */
   if (!(ret= db_repository->drop_event(thd, dbname, name, if_exists)))
+  {
     event_queue->drop_event(thd, dbname, name);
+    /* Binlog the drop event. */
+    if (mysql_bin_log.is_open() && (thd->query_length > 0))
+    {
+      thd->clear_error();
+      thd->binlog_query(THD::MYSQL_QUERY_TYPE,
+                        thd->query, thd->query_length, FALSE, FALSE);
+    }
+  }
   pthread_mutex_unlock(&LOCK_event_metadata);
   DBUG_RETURN(ret);
 }

--- 1.25/sql/event_db_repository.cc	2007-03-23 18:14:01 +03:00
+++ 1.26/sql/event_db_repository.cc	2007-04-03 14:34:31 +04:00
@@ -94,7 +94,7 @@
   },
   {
     { C_STRING_WITH_LEN("status") },
-    { C_STRING_WITH_LEN("enum('ENABLED','DISABLED')") },
+    { C_STRING_WITH_LEN("enum('ENABLED','DISABLED','SLAVESIDE_DISABLED')") },
     {NULL, 0}
   },
   {
@@ -120,6 +120,11 @@
     { C_STRING_WITH_LEN("utf8") }
   },
   {
+    { C_STRING_WITH_LEN("originator") },
+    { C_STRING_WITH_LEN("int(10)") },
+    {NULL, 0}
+  },
+  {
     { C_STRING_WITH_LEN("time_zone") },
     { C_STRING_WITH_LEN("char(64)") },
     { C_STRING_WITH_LEN("latin1") }
@@ -175,6 +180,9 @@
 
   fields[ET_FIELD_STATUS]->store((longlong)et->status, TRUE);
 
+  fields[ET_FIELD_ORIGINATOR]->store((longlong)et->originator, TRUE);
+
+
   /*
     Change the SQL_MODE only if body was present in an ALTER EVENT and of course
     always during CREATE EVENT.
@@ -564,7 +572,6 @@
     goto err;
   }
 
-
   DBUG_PRINT("info", ("name: %.*s", parse_data->name.length,
              parse_data->name.str));
 
@@ -631,6 +638,8 @@
   */
   if ((ret= mysql_event_fill_row(thd, table, parse_data, FALSE)))
     goto err;
+
+  table->field[ET_FIELD_STATUS]->store((longlong)parse_data->status, TRUE);
 
   /* Close active transaction only if We are going to modify disk */
   if (end_active_trans(thd))

--- 1.14/sql/event_db_repository.h	2007-03-29 17:54:53 +04:00
+++ 1.15/sql/event_db_repository.h	2007-04-03 14:29:58 +04:00
@@ -63,7 +63,7 @@
   update_event(THD *thd, Event_parse_data *parse_data, LEX_STRING *new_dbname,
                LEX_STRING *new_name);
 
-  bool 
+  bool
   drop_event(THD *thd, LEX_STRING db, LEX_STRING name, bool drop_if_exists);
 
   void
@@ -99,5 +99,5 @@
   Event_db_repository(const Event_db_repository &);
   void operator=(Event_db_repository &);
 };
- 
+
 #endif /* _EVENT_DB_REPOSITORY_H_ */

--- 1.29/sql/event_queue.cc	2007-03-23 19:14:06 +03:00
+++ 1.30/sql/event_queue.cc	2007-04-03 14:29:58 +04:00
@@ -189,7 +189,8 @@
   DBUG_PRINT("enter", ("thd: 0x%lx et=%s.%s", (long) thd,
              new_element->dbname.str, new_element->name.str));
 
-  if (new_element->status == Event_queue_element::DISABLED)
+  if ((new_element->status == Event_queue_element::DISABLED) 
+      || (new_element->status == Event_queue_element::SLAVESIDE_DISABLED))
     delete new_element;
   else
   {
@@ -225,7 +226,8 @@
   DBUG_ENTER("Event_queue::update_event");
   DBUG_PRINT("enter", ("thd: 0x%lx  et=[%s.%s]", (long) thd, dbname.str, name.str));
 
-  if (new_element->status == Event_queue_element::DISABLED)
+  if ((new_element->status == Event_queue_element::DISABLED) ||
+      (new_element->status == Event_queue_element::SLAVESIDE_DISABLED))
   {
     DBUG_PRINT("info", ("The event is disabled."));
     /*

--- 1.92/sql/event_data_objects.cc	2007-03-27 21:09:51 +04:00
+++ 1.93/sql/event_data_objects.cc	2007-04-03 14:29:58 +04:00
@@ -101,7 +101,8 @@
 */
 
 Event_parse_data::Event_parse_data()
-  :on_completion(ON_COMPLETION_DROP), status(ENABLED), do_not_create(FALSE),
+  :on_completion(Event_basic::ON_COMPLETION_DROP), 
+   status(Event_basic::ENABLED), do_not_create(FALSE),
    item_starts(NULL), item_ends(NULL), item_execute_at(NULL),
    starts_null(TRUE), ends_null(TRUE), execute_at_null(TRUE),
    item_expression(NULL), expression(0)
@@ -243,7 +244,7 @@
   if (ltime_utc >= (my_time_t) thd->query_start())
     return;
 
-  if (on_completion == ON_COMPLETION_DROP)
+  if (on_completion == Event_basic::ON_COMPLETION_DROP)
   {
     switch (thd->lex->sql_command) {
     case SQLCOM_CREATE_EVENT:
@@ -260,9 +261,9 @@
 
     do_not_create= TRUE;
   }
-  else if (status == ENABLED)
+  else if (status == Event_basic::ENABLED)
   {
-    status= DISABLED;
+    status= Event_basic::DISABLED;
     push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
                  ER_EVENT_EXEC_TIME_IN_THE_PAST,
                  ER(ER_EVENT_EXEC_TIME_IN_THE_PAST));
@@ -588,9 +589,9 @@
   init_name(thd, identifier);
 
   init_definer(thd);
-
   ret= init_execute_at(thd) || init_interval(thd) || init_starts(thd) ||
        init_ends(thd);
+  check_originator_id(thd);
   DBUG_RETURN(ret);
 }
 
@@ -638,6 +639,31 @@
 
 
 /*
+  Set the originator id of the event to the server_id if executing on
+  the master or set to the server_id of the master if executing on 
+  the slave. If executing on slave, also set status to SLAVESIDE_DISABLED.
+
+  SYNOPSIS
+    Event_parse_data::check_originator_id()
+*/
+void Event_parse_data::check_originator_id(THD *thd)
+{
+  /* Disable replicated events on slave. */
+  if ((thd->system_thread == SYSTEM_THREAD_SLAVE_SQL) ||
+      (thd->system_thread == SYSTEM_THREAD_SLAVE_IO))
+  {
+    DBUG_PRINT("info", ("Invoked object status set to SLAVESIDE_DISABLED."));
+    if ((status == Event_basic::ENABLED) ||
+        (status == Event_basic::DISABLED))
+      status = Event_basic::SLAVESIDE_DISABLED;
+    originator = thd->server_id;
+  }
+  else
+    originator = server_id;
+}
+
+
+/*
   Constructor
 
   SYNOPSIS
@@ -995,8 +1021,23 @@
     goto error;
 
   DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", name.str, ptr));
-  status= (ptr[0]=='E'? Event_queue_element::ENABLED:
-                        Event_queue_element::DISABLED);
+
+  /* Set event status (ENABLED | SLAVESIDE_DISABLED | DISABLED) */
+  switch (ptr[0])
+  {
+  case 'E' :
+    status = Event_queue_element::ENABLED;
+    break;
+  case 'S' :
+    status = Event_queue_element::SLAVESIDE_DISABLED;
+    break;
+  case 'D' :
+    status = Event_queue_element::DISABLED;
+    break;
+  }
+  if ((ptr= get_field(&mem_root, table->field[ET_FIELD_ORIGINATOR])) == NullS)
+    goto error;
+  originator = table->field[ET_FIELD_ORIGINATOR]->val_int(); 
 
   /* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
   if ((ptr= get_field(&mem_root,
@@ -1343,7 +1384,7 @@
                        (long) starts, (long) ends, (long) last_executed,
                        (long) this));
 
-  if (status == Event_queue_element::DISABLED)
+  if (status != Event_queue_element::ENABLED)
   {
     DBUG_PRINT("compute_next_execution_time",
                ("Event %s is DISABLED", name.str));
@@ -1640,6 +1681,13 @@
     status_changed= FALSE;
   }
 
+  /* 
+    Turn off row binlogging of event timing updates. These are not used
+    for RBR of events replicated to the slave.
+  */
+  if (thd->current_stmt_binlog_row_based)
+    thd->clear_current_stmt_binlog_row_based();
+
   if ((table->file->ha_update_row(table->record[1], table->record[0])))
     ret= TRUE;
 
@@ -1730,6 +1778,8 @@
 
   if (status == Event_timed::ENABLED)
     buf->append(STRING_WITH_LEN("ENABLE"));
+  else if (status == Event_timed::SLAVESIDE_DISABLED)
+    buf->append(STRING_WITH_LEN("SLAVESIDE_DISABLE"));
   else
     buf->append(STRING_WITH_LEN("DISABLE"));
 

--- 1.19/sql/event_data_objects.h	2007-03-27 21:09:51 +04:00
+++ 1.20/sql/event_data_objects.h	2007-04-03 14:29:58 +04:00
@@ -22,11 +22,9 @@
 #define EVEX_BAD_PARAMS         -5
 #define EVEX_MICROSECOND_UNSUP  -6
 
-
 class sp_head;
 class Sql_alloc;
 
-
 class Event_queue_element_for_exec
 {
 public:
@@ -54,6 +52,24 @@
   MEM_ROOT mem_root;
 
 public:
+  /*
+    ENABLED = feature can function normally (is turned on)
+    SLAVESIDE_DISABLED = feature is turned off on slave
+    DISABLED = feature is turned off
+  */
+  enum enum_status
+  {
+    ENABLED = 1,
+    DISABLED,
+    SLAVESIDE_DISABLED  
+  };
+
+  enum enum_on_completion
+  {
+    ON_COMPLETION_DROP = 1,
+    ON_COMPLETION_PRESERVE
+  };
+
   LEX_STRING dbname;
   LEX_STRING name;
   LEX_STRING definer;// combination of user and host
@@ -83,20 +99,9 @@
   bool last_executed_changed;
 
 public:
-  enum enum_status
-  {
-    ENABLED = 1,
-    DISABLED
-  };
-
-  enum enum_on_completion
-  {
-    ON_COMPLETION_DROP = 1,
-    ON_COMPLETION_PRESERVE
-  };
-
-  enum enum_on_completion on_completion;
-  enum enum_status status;
+  int on_completion;
+  int status;
+  longlong originator;
 
   my_time_t last_executed;
   my_time_t execute_at;
@@ -198,19 +203,10 @@
 class Event_parse_data : public Sql_alloc
 {
 public:
-  enum enum_status
-  {
-    ENABLED = 1,
-    DISABLED
-  };
 
-  enum enum_on_completion
-  {
-    ON_COMPLETION_DROP = 1,
-    ON_COMPLETION_PRESERVE
-  };
-  enum enum_on_completion on_completion;
-  enum enum_status status;
+  int on_completion;
+  int status;
+  longlong originator;
   /*
     do_not_create will be set if STARTS time is in the past and
     on_completion == ON_COMPLETION_DROP.
@@ -280,6 +276,7 @@
   check_if_in_the_past(THD *thd, my_time_t ltime_utc);
 
   Event_parse_data(const Event_parse_data &);	/* Prevent use of these */
+  void check_originator_id(THD *thd);
   void operator=(Event_parse_data &);
 };
 

--- 1.151/sql/share/errmsg.txt	2007-03-27 22:15:47 +04:00
+++ 1.152/sql/share/errmsg.txt	2007-04-03 14:30:04 +04:00
@@ -6055,3 +6055,5 @@
         eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. Event has not been created"
 ER_EVENT_CANNOT_ALTER_IN_THE_PAST
         eng "Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. Event has not been altered"
+ER_SLAVE_INCIDENT
+        eng "The incident %s occured on the master. Message: %-.64s"

--- 1.126/sql/sql_view.cc	2007-03-23 00:05:42 +03:00
+++ 1.127/sql/sql_view.cc	2007-04-03 14:30:00 +04:00
@@ -679,7 +679,7 @@
   char md5[MD5_BUFF_LENGTH];
   bool can_be_merged;
   char dir_buff[FN_REFLEN], path_buff[FN_REFLEN];
-  const uchar *endp;
+  const char *endp;
   LEX_STRING dir, file, path;
   DBUG_ENTER("mysql_register_view");
 
@@ -763,9 +763,9 @@
   view->query.str= (char*)str.ptr();
   view->query.length= str.length()-1; // we do not need last \0
   view->source.str= thd->query + thd->lex->create_view_select_start;
-  endp= (uchar*) view->source.str;
-  endp= skip_rear_comments(endp, (uchar*) (thd->query + thd->query_length));
-  view->source.length= endp - (uchar*) view->source.str;
+  endp= view->source.str;
+  endp= skip_rear_comments(endp, thd->query + thd->query_length);
+  view->source.length= endp - view->source.str;
   view->file_version= 1;
   view->calc_md5(md5);
   view->md5.str= md5;
@@ -974,7 +974,7 @@
     now Lex placed in statement memory
   */
   table->view= lex= thd->lex= (LEX*) new(thd->mem_root) st_lex_local;
-  lex_start(thd, (uchar*)table->query.str, table->query.length);
+  lex_start(thd, table->query.str, table->query.length);
   view_select= &lex->select_lex;
   view_select->select_number= ++thd->select_number;
   {

--- 1.425/sql/ha_ndbcluster.cc	2007-03-30 14:35:03 +04:00
+++ 1.426/sql/ha_ndbcluster.cc	2007-04-03 14:29:58 +04:00
@@ -6367,7 +6367,7 @@
   LEX *old_lex= thd->lex, newlex;
   thd->lex= &newlex;
   newlex.current_select= NULL;
-  lex_start(thd, (const uchar*) "", 0);
+  lex_start(thd, "", 0);
   int res= ha_create_table_from_engine(thd, db, table_name);
   thd->lex= old_lex;
   return res;

--- 1.9/sql/sql_servers.cc	2007-03-23 18:19:51 +03:00
+++ 1.10/sql/sql_servers.cc	2007-04-03 14:30:00 +04:00
@@ -16,6 +16,21 @@
 
 /*
   The servers are saved in the system table "servers"
+  
+  Currently, when the user performs an ALTER SERVER or a DROP SERVER
+  operation, it will cause all open tables which refer to the named
+  server connection to be flushed. This may cause some undesirable
+  behaviour with regard to currently running transactions. It is 
+  expected that the DBA knows what s/he is doing when s/he performs
+  the ALTER SERVER or DROP SERVER operation.
+  
+  TODO:
+  It is desirable for us to implement a callback mechanism instead where
+  callbacks can be registered for specific server protocols. The callback
+  will be fired when such a server name has been created/altered/dropped
+  or when statistics are to be gathered such as how many actual connections.
+  Storage engines etc will be able to make use of the callback so that
+  currently running transactions etc will not be disrupted.
 */
 
 #include "mysql_priv.h"
@@ -25,15 +40,43 @@
 #include "sp_head.h"
 #include "sp.h"
 
-static my_bool servers_load(THD *thd, TABLE_LIST *tables);
-HASH servers_cache;
-pthread_mutex_t servers_cache_mutex;                // To init the hash
-uint servers_cache_initialised=FALSE;
-/* Version of server table. incremented by servers_load */
-static uint servers_version=0;
+/*
+  We only use 1 mutex to guard the data structures - THR_LOCK_servers.
+  Read locked when only reading data and write-locked for all other access.
+*/
+
+static HASH servers_cache;
 static MEM_ROOT mem;
 static rw_lock_t THR_LOCK_servers;
 
+static bool get_server_from_table_to_cache(TABLE *table);
+
+/* insert functions */
+static int insert_server(THD *thd, FOREIGN_SERVER *server_options);
+static int insert_server_record(TABLE *table, FOREIGN_SERVER *server);
+static int insert_server_record_into_cache(FOREIGN_SERVER *server);
+static void prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options,
+                                             FOREIGN_SERVER *server);
+/* drop functions */ 
+static int delete_server_record(TABLE *table,
+                                char *server_name,
+                                int server_name_length);
+static int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options);
+
+/* update functions */
+static void prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options,
+                                             FOREIGN_SERVER *existing,
+                                             FOREIGN_SERVER *altered);
+static int update_server(THD *thd, FOREIGN_SERVER *existing, 
+					     FOREIGN_SERVER *altered);
+static int update_server_record(TABLE *table, FOREIGN_SERVER *server);
+static int update_server_record_in_cache(FOREIGN_SERVER *existing,
+                                         FOREIGN_SERVER *altered);
+/* utility functions */
+static void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to);
+
+
+
 static byte *servers_cache_get_key(FOREIGN_SERVER *server, uint *length,
 			       my_bool not_used __attribute__((unused)))
 {
@@ -46,6 +89,7 @@
   DBUG_RETURN((byte*) server->server_name);
 }
 
+
 /*
   Initialize structures responsible for servers used in federated
   server scheme information for them from the server
@@ -65,35 +109,27 @@
     1	Could not initialize servers
 */
 
-my_bool servers_init(bool dont_read_servers_table)
+bool servers_init(bool dont_read_servers_table)
 {
   THD  *thd;
-  my_bool return_val= 0;
+  bool return_val= FALSE;
   DBUG_ENTER("servers_init");
 
   /* init the mutex */
-  if (pthread_mutex_init(&servers_cache_mutex, MY_MUTEX_INIT_FAST))
-    DBUG_RETURN(1);
-
   if (my_rwlock_init(&THR_LOCK_servers, NULL))
-    DBUG_RETURN(1);
+    DBUG_RETURN(TRUE);
 
   /* initialise our servers cache */
   if (hash_init(&servers_cache, system_charset_info, 32, 0, 0,
                 (hash_get_key) servers_cache_get_key, 0, 0))
   {
-    return_val= 1; /* we failed, out of memory? */
+    return_val= TRUE; /* we failed, out of memory? */
     goto end;
   }
 
   /* Initialize the mem root for data */
   init_alloc_root(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
 
-  /*
-    at this point, the cache is initialised, let it be known
-  */
-  servers_cache_initialised= TRUE;
-
   if (dont_read_servers_table)
     goto end;
 
@@ -101,7 +137,7 @@
     To be able to run this from boot, we allocate a temporary THD
   */
   if (!(thd=new THD))
-    DBUG_RETURN(1);
+    DBUG_RETURN(TRUE);
   thd->thread_stack= (char*) &thd;
   thd->store_globals();
   /*
@@ -131,19 +167,13 @@
     TRUE   Error
 */
 
-static my_bool servers_load(THD *thd, TABLE_LIST *tables)
+static bool servers_load(THD *thd, TABLE_LIST *tables)
 {
   TABLE *table;
   READ_RECORD read_record_info;
-  my_bool return_val= TRUE;
+  bool return_val= TRUE;
   DBUG_ENTER("servers_load");
 
-  if (!servers_cache_initialised)
-    DBUG_RETURN(0);
-
-  /* need to figure out how to utilise this variable */
-  servers_version++; /* servers updated */
-
   /* first, send all cached rows to sleep with the fishes, oblivion!
      I expect this crappy comment replaced */
   free_root(&mem, MYF(MY_MARK_BLOCKS_FREE));
@@ -157,7 +187,7 @@
       goto end;
   }
 
-  return_val=0;
+  return_val= FALSE;
 
 end:
   end_read_record(&read_record_info);
@@ -184,10 +214,10 @@
     TRUE   Failure
 */
 
-my_bool servers_reload(THD *thd)
+bool servers_reload(THD *thd)
 {
   TABLE_LIST tables[1];
-  my_bool return_val= 1;
+  bool return_val= TRUE;
   DBUG_ENTER("servers_reload");
 
   if (thd->locked_tables)
@@ -197,10 +227,9 @@
     close_thread_tables(thd);
   }
 
-  /*
-    To avoid deadlocks we should obtain table locks before
-    obtaining servers_cache->lock mutex.
-  */
+  DBUG_PRINT("info", ("locking servers_cache"));
+  rw_wrlock(&THR_LOCK_servers);
+
   bzero((char*) tables, sizeof(tables));
   tables[0].alias= tables[0].table_name= (char*) "servers";
   tables[0].db= (char*) "mysql";
@@ -213,12 +242,6 @@
     goto end;
   }
 
-  DBUG_PRINT("info", ("locking servers_cache"));
-  VOID(pthread_mutex_lock(&servers_cache_mutex));
-
-  //old_servers_cache= servers_cache;
-  //old_mem=mem;
-
   if ((return_val= servers_load(thd, tables)))
   {					// Error. Revert to old list
     /* blast, for now, we have no servers, discuss later way to preserve */
@@ -227,14 +250,14 @@
     servers_free();
   }
 
-  DBUG_PRINT("info", ("unlocking servers_cache"));
-  VOID(pthread_mutex_unlock(&servers_cache_mutex));
-
 end:
   close_thread_tables(thd);
+  DBUG_PRINT("info", ("unlocking servers_cache"));
+  rw_unlock(&THR_LOCK_servers);
   DBUG_RETURN(return_val);
 }
 
+
 /*
   Initialize structures responsible for servers used in federated
   server scheme information for them from the server
@@ -261,7 +284,8 @@
     1	could not insert server struct into global servers cache
 */
 
-my_bool get_server_from_table_to_cache(TABLE *table)
+static bool 
+get_server_from_table_to_cache(TABLE *table)
 {
   /* alloc a server struct */
   char *ptr;
@@ -309,68 +333,6 @@
   DBUG_RETURN(FALSE);
 }
 
-/*
-  SYNOPSIS
-    server_exists_in_table()
-      THD   *thd - thread pointer
-      LEX_SERVER_OPTIONS *server_options - pointer to Lex->server_options
-
-  NOTES
-    This function takes a LEX_SERVER_OPTIONS struct, which is very much the
-    same type of structure as a FOREIGN_SERVER, it contains the values parsed
-    in any one of the [CREATE|DELETE|DROP] SERVER statements. Using the
-    member "server_name", index_read_idx either founds the record and returns
-    1, or doesn't find the record, and returns 0
-
-  RETURN VALUES
-    0   record not found
-    1	record found
-*/
-
-my_bool server_exists_in_table(THD *thd, LEX_SERVER_OPTIONS *server_options)
-{
-  int result= 1;
-  int error= 0;
-  TABLE_LIST tables;
-  TABLE *table;
-  DBUG_ENTER("server_exists");
-
-  bzero((char*) &tables, sizeof(tables));
-  tables.db= (char*) "mysql";
-  tables.alias= tables.table_name= (char*) "servers";
-
-  /* need to open before acquiring THR_LOCK_plugin or it will deadlock */
-  if (! (table= open_ltable(thd, &tables, TL_WRITE)))
-    DBUG_RETURN(TRUE);
-
-  table->use_all_columns();
-
-  rw_wrlock(&THR_LOCK_servers);
-  VOID(pthread_mutex_lock(&servers_cache_mutex));
-
-  /* set the field that's the PK to the value we're looking for */
-  table->field[0]->store(server_options->server_name,
-                         server_options->server_name_length,
-                         system_charset_info);
-
-  if ((error= table->file->index_read_idx(table->record[0], 0,
-                                   (byte *)table->field[0]->ptr, HA_WHOLE_KEY,
-                                   HA_READ_KEY_EXACT)))
-  {
-    if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
-    {
-      table->file->print_error(error, MYF(0));
-      result= -1;
-    }
-    result= 0;
-    DBUG_PRINT("info",("record for server '%s' not found!",
-                       server_options->server_name));
-  }
-
-  VOID(pthread_mutex_unlock(&servers_cache_mutex));
-  rw_unlock(&THR_LOCK_servers);
-  DBUG_RETURN(result);
-}
 
 /*
   SYNOPSIS
@@ -382,15 +344,18 @@
     This function takes a server object that is has all members properly
     prepared, ready to be inserted both into the mysql.servers table and
     the servers cache.
+	
+    THR_LOCK_servers must be write locked.
 
   RETURN VALUES
     0  - no error
     other - error code
 */
 
-int insert_server(THD *thd, FOREIGN_SERVER *server)
+static int 
+insert_server(THD *thd, FOREIGN_SERVER *server)
 {
-  int error= 0;
+  int error= -1;
   TABLE_LIST tables;
   TABLE *table;
 
@@ -402,13 +367,7 @@
 
   /* need to open before acquiring THR_LOCK_plugin or it will deadlock */
   if (! (table= open_ltable(thd, &tables, TL_WRITE)))
-    DBUG_RETURN(TRUE);
-
-  /* lock mutex to make sure no changes happen */
-  VOID(pthread_mutex_lock(&servers_cache_mutex));
-
-  /* lock table */
-  rw_wrlock(&THR_LOCK_servers);
+    goto end;
 
   /* insert the server into the table */
   if ((error= insert_server_record(table, server)))
@@ -419,12 +378,10 @@
     goto end;
 
 end:
-  /* unlock the table */
-  rw_unlock(&THR_LOCK_servers);
-  VOID(pthread_mutex_unlock(&servers_cache_mutex));
   DBUG_RETURN(error);
 }
 
+
 /*
   SYNOPSIS
     int insert_server_record_into_cache()
@@ -434,13 +391,16 @@
     This function takes a FOREIGN_SERVER pointer to an allocated (root mem)
     and inserts it into the global servers cache
 
+    THR_LOCK_servers must be write locked.
+
   RETURN VALUE
     0   - no error
     >0  - error code
 
 */
 
-int insert_server_record_into_cache(FOREIGN_SERVER *server)
+static int 
+insert_server_record_into_cache(FOREIGN_SERVER *server)
 {
   int error=0;
   DBUG_ENTER("insert_server_record_into_cache");
@@ -461,6 +421,7 @@
   DBUG_RETURN(error);
 }
 
+
 /*
   SYNOPSIS
     store_server_fields()
@@ -478,7 +439,8 @@
 
 */
 
-void store_server_fields(TABLE *table, FOREIGN_SERVER *server)
+static void 
+store_server_fields(TABLE *table, FOREIGN_SERVER *server)
 {
 
   table->use_all_columns();
@@ -539,6 +501,7 @@
 
   */
 
+static
 int insert_server_record(TABLE *table, FOREIGN_SERVER *server)
 {
   int error;
@@ -605,9 +568,11 @@
 
 int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
 {
-  int error= 0;
+  int error;
   TABLE_LIST tables;
   TABLE *table;
+  LEX_STRING name= { server_options->server_name, 
+                     server_options->server_name_length };
 
   DBUG_ENTER("drop_server");
   DBUG_PRINT("info", ("server name server->server_name %s",
@@ -617,28 +582,35 @@
   tables.db= (char*) "mysql";
   tables.alias= tables.table_name= (char*) "servers";
 
-  /* need to open before acquiring THR_LOCK_plugin or it will deadlock */
-  if (! (table= open_ltable(thd, &tables, TL_WRITE)))
-    DBUG_RETURN(TRUE);
-
   rw_wrlock(&THR_LOCK_servers);
-  VOID(pthread_mutex_lock(&servers_cache_mutex));
 
+  /* hit the memory hit first */
+  if ((error= delete_server_record_in_cache(server_options)))
+    goto end;
 
-  if ((error= delete_server_record(table,
-                                   server_options->server_name,
-                                   server_options->server_name_length)))
+  if (! (table= open_ltable(thd, &tables, TL_WRITE)))
+  {
+    error= my_errno;
     goto end;
+  }
 
+  error= delete_server_record(table, name.str, name.length);
 
-  if ((error= delete_server_record_in_cache(server_options)))
-    goto end;
+  /* close the servers table before we call closed_cached_connection_tables */
+  close_thread_tables(thd);
+
+  if (close_cached_connection_tables(thd, TRUE, &name))
+  {
+    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                        ER_UNKNOWN_ERROR, "Server connection in use");
+  }
 
 end:
-  VOID(pthread_mutex_unlock(&servers_cache_mutex));
   rw_unlock(&THR_LOCK_servers);
   DBUG_RETURN(error);
 }
+
+
 /*
 
   SYNOPSIS
@@ -657,10 +629,10 @@
 
 */
 
-int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options)
+static int 
+delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options)
 {
-
-  int error= 0;
+  int error= ER_FOREIGN_SERVER_DOESNT_EXIST;
   FOREIGN_SERVER *server;
   DBUG_ENTER("delete_server_record_in_cache");
 
@@ -676,7 +648,7 @@
     DBUG_PRINT("info", ("server_name %s length %d not found!",
                         server_options->server_name,
                         server_options->server_name_length));
-    // what should be done if not found in the cache?
+    goto end;
   }
   /*
     We succeded in deletion of the server to the table, now delete
@@ -686,14 +658,15 @@
                      server->server_name,
                      server->server_name_length));
 
-  if (server)
-    VOID(hash_delete(&servers_cache, (byte*) server));
-
-  servers_version++; /* servers updated */
+  VOID(hash_delete(&servers_cache, (byte*) server));
+  
+  error= 0;
 
+end:
   DBUG_RETURN(error);
 }
 
+
 /*
 
   SYNOPSIS
@@ -713,6 +686,8 @@
     table for the particular server via the call to update_server_record,
     and in the servers_cache via update_server_record_in_cache. 
 
+    THR_LOCK_servers must be write locked.
+
   RETURN VALUE
     0 - no error
     >0 - error code
@@ -721,7 +696,7 @@
 
 int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered)
 {
-  int error= 0;
+  int error;
   TABLE *table;
   TABLE_LIST tables;
   DBUG_ENTER("update_server");
@@ -731,19 +706,26 @@
   tables.alias= tables.table_name= (char*)"servers";
 
   if (!(table= open_ltable(thd, &tables, TL_WRITE)))
-    DBUG_RETURN(1);
+  {
+    error= my_errno;
+    goto end;
+  }
 
-  rw_wrlock(&THR_LOCK_servers);
   if ((error= update_server_record(table, altered)))
     goto end;
 
-  update_server_record_in_cache(existing, altered);
+  error= update_server_record_in_cache(existing, altered);
+
+  /*
+	Perform a reload so we don't have a 'hole' in our mem_root
+  */
+  servers_load(thd, &tables);
 
 end:
-  rw_unlock(&THR_LOCK_servers);
   DBUG_RETURN(error);
 }
 
+
 /*
 
   SYNOPSIS
@@ -760,6 +742,8 @@
     HASH, then the updated record inserted, in essence replacing the old
     record.
 
+    THR_LOCK_servers must be write locked.
+
   RETURN VALUE
     0 - no error
     1 - error
@@ -790,13 +774,13 @@
   {
     DBUG_PRINT("info", ("had a problem inserting server %s at %lx",
                         altered->server_name, (long unsigned int) altered));
-    error= 1;
+    error= ER_OUT_OF_RESOURCES;
   }
 
-  servers_version++; /* servers updated */
   DBUG_RETURN(error);
 }
 
+
 /*
 
   SYNOPSIS
@@ -829,9 +813,9 @@
     to->password= strdup_root(&mem, from->password);
   if (to->port == -1)
     to->port= from->port;
-  if (!to->socket)
+  if (!to->socket && from->socket)
     to->socket= strdup_root(&mem, from->socket);
-  if (!to->scheme)
+  if (!to->scheme && from->scheme)
     to->scheme= strdup_root(&mem, from->scheme);
   if (!to->owner)
     to->owner= strdup_root(&mem, from->owner);
@@ -839,6 +823,7 @@
   DBUG_VOID_RETURN;
 }
 
+
 /*
 
   SYNOPSIS
@@ -861,7 +846,9 @@
 
 */
 
-int update_server_record(TABLE *table, FOREIGN_SERVER *server)
+
+static int 
+update_server_record(TABLE *table, FOREIGN_SERVER *server)
 {
   int error=0;
   DBUG_ENTER("update_server_record");
@@ -876,10 +863,7 @@
                                    HA_READ_KEY_EXACT)))
   {
     if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
-    {
       table->file->print_error(error, MYF(0));
-      error= 1;
-    }
     DBUG_PRINT("info",("server not found!"));
     error= ER_FOREIGN_SERVER_DOESNT_EXIST;
   }
@@ -899,6 +883,7 @@
   DBUG_RETURN(error);
 }
 
+
 /*
 
   SYNOPSIS
@@ -914,11 +899,11 @@
 
 */
 
-int delete_server_record(TABLE *table,
-                         char *server_name,
-                         int server_name_length)
+static int 
+delete_server_record(TABLE *table,
+                     char *server_name, int server_name_length)
 {
-  int error= 0;
+  int error;
   DBUG_ENTER("delete_server_record");
   table->use_all_columns();
 
@@ -930,10 +915,7 @@
                                    HA_READ_KEY_EXACT)))
   {
     if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
-    {
       table->file->print_error(error, MYF(0));
-      error= 1;
-    }
     DBUG_PRINT("info",("server not found!"));
     error= ER_FOREIGN_SERVER_DOESNT_EXIST;
   }
@@ -962,28 +944,35 @@
 
 int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
 {
-  int error;
+  int error= ER_FOREIGN_SERVER_EXISTS;
   FOREIGN_SERVER *server;
 
   DBUG_ENTER("create_server");
   DBUG_PRINT("info", ("server_options->server_name %s",
                       server_options->server_name));
 
+  rw_wrlock(&THR_LOCK_servers);
+
+  /* hit the memory first */
+  if (hash_search(&servers_cache, (byte*) server_options->server_name,
+				   server_options->server_name_length))
+    goto end;
+
   server= (FOREIGN_SERVER *)alloc_root(&mem,
                                        sizeof(FOREIGN_SERVER));
 
-  if ((error= prepare_server_struct_for_insert(server_options, server)))
-    goto end;
+  prepare_server_struct_for_insert(server_options, server);
 
-  if ((error= insert_server(thd, server)))
-    goto end;
+  error= insert_server(thd, server);
 
   DBUG_PRINT("info", ("error returned %d", error));
 
 end:
+  rw_unlock(&THR_LOCK_servers);
   DBUG_RETURN(error);
 }
 
+
 /*
 
   SYNOPSIS
@@ -1000,37 +989,44 @@
 
 int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
 {
-  int error= 0;
+  int error= ER_FOREIGN_SERVER_DOESNT_EXIST;
   FOREIGN_SERVER *altered, *existing;
+  LEX_STRING name= { server_options->server_name, 
+                     server_options->server_name_length };
   DBUG_ENTER("alter_server");
   DBUG_PRINT("info", ("server_options->server_name %s",
                       server_options->server_name));
 
+  rw_wrlock(&THR_LOCK_servers);
+
+  if (!(existing= (FOREIGN_SERVER *) hash_search(&servers_cache,
+                                                 (byte*) name.str,
+                                                 name.length)))
+    goto end;
+
   altered= (FOREIGN_SERVER *)alloc_root(&mem,
                                         sizeof(FOREIGN_SERVER));
 
-  VOID(pthread_mutex_lock(&servers_cache_mutex));
+  prepare_server_struct_for_update(server_options, existing, altered);
 
-  if (!(existing= (FOREIGN_SERVER *) hash_search(&servers_cache,
-                                                 (byte*) server_options->server_name,
-                                               server_options->server_name_length)))
-  {
-    error= ER_FOREIGN_SERVER_DOESNT_EXIST;
-    goto end;
-  }
+  error= update_server(thd, existing, altered);
 
-  if ((error= prepare_server_struct_for_update(server_options, existing, altered)))
-    goto end;
+  /* close the servers table before we call closed_cached_connection_tables */
+  close_thread_tables(thd);
 
-  if ((error= update_server(thd, existing, altered)))
-    goto end;
+  if (close_cached_connection_tables(thd, FALSE, &name))
+  {
+    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                        ER_UNKNOWN_ERROR, "Server connection in use");
+  }
 
 end:
   DBUG_PRINT("info", ("error returned %d", error));
-  VOID(pthread_mutex_unlock(&servers_cache_mutex));
+  rw_unlock(&THR_LOCK_servers);
   DBUG_RETURN(error);
 }
 
+
 /*
 
   SYNOPSIS
@@ -1041,19 +1037,17 @@
   NOTES
 
   RETURN VALUE
-    0 - no error
+    none
 
 */
 
-int prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options,
-                                     FOREIGN_SERVER *server)
+static void
+prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options,
+                                 FOREIGN_SERVER *server)
 {
-  int error;
   char *unset_ptr= (char*)"";
   DBUG_ENTER("prepare_server_struct");
 
-  error= 0;
-
   /* these two MUST be set */
   server->server_name= strdup_root(&mem, server_options->server_name);
   server->server_name_length= server_options->server_name_length;
@@ -1083,7 +1077,7 @@
   server->owner= server_options->owner ?
     strdup_root(&mem, server_options->owner) : unset_ptr;
 
-  DBUG_RETURN(error);
+  DBUG_VOID_RETURN;
 }
 
 /*
@@ -1099,13 +1093,12 @@
 
 */
 
-int prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options,
-                                     FOREIGN_SERVER *existing,
-                                     FOREIGN_SERVER *altered)
+static void
+prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options,
+                                 FOREIGN_SERVER *existing,
+                                 FOREIGN_SERVER *altered)
 {
-  int error;
   DBUG_ENTER("prepare_server_struct_for_update");
-  error= 0;
 
   altered->server_name= strdup_root(&mem, server_options->server_name);
   altered->server_name_length= server_options->server_name_length;
@@ -1156,7 +1149,7 @@
     (strcmp(server_options->owner, existing->owner))) ?
       strdup_root(&mem, server_options->owner) : 0;
 
-  DBUG_RETURN(error);
+  DBUG_VOID_RETURN;
 }
 
 /*
@@ -1175,16 +1168,65 @@
 void servers_free(bool end)
 {
   DBUG_ENTER("servers_free");
-  if (!servers_cache_initialised)
+  if (!hash_inited(&servers_cache))
+    DBUG_VOID_RETURN;
+  if (!end)
+  {
+    free_root(&mem, MYF(MY_MARK_BLOCKS_FREE));
+	my_hash_reset(&servers_cache);
     DBUG_VOID_RETURN;
-  VOID(pthread_mutex_destroy(&servers_cache_mutex));
-  servers_cache_initialised=0;
+  }
+  rwlock_destroy(&THR_LOCK_servers);
   free_root(&mem,MYF(0));
   hash_free(&servers_cache);
   DBUG_VOID_RETURN;
 }
 
 
+/*
+  SYNOPSIS
+
+  clone_server(MEM_ROOT *mem_root, FOREIGN_SERVER *orig, FOREIGN_SERVER *buff)
+
+  Create a clone of FOREIGN_SERVER. If the supplied mem_root is of
+  thd->mem_root then the copy is automatically disposed at end of statement.
+
+  NOTES
+
+  ARGS
+   MEM_ROOT pointer (strings are copied into this mem root) 
+   FOREIGN_SERVER pointer (made a copy of)
+   FOREIGN_SERVER buffer (if not-NULL, this pointer is returned)
+
+  RETURN VALUE
+   FOREIGN_SEVER pointer (copy of one supplied FOREIGN_SERVER)
+*/
+
+static FOREIGN_SERVER *clone_server(MEM_ROOT *mem, const FOREIGN_SERVER *server,
+                                    FOREIGN_SERVER *buffer)
+{
+  DBUG_ENTER("sql_server.cc:clone_server");
+
+  if (!buffer)
+    buffer= (FOREIGN_SERVER *) alloc_root(mem, sizeof(FOREIGN_SERVER));
+
+  buffer->server_name= strmake_root(mem, server->server_name,
+                                    server->server_name_length);
+  buffer->port= server->port;
+  buffer->server_name_length= server->server_name_length;
+  
+  /* TODO: We need to examine which of these can really be NULL */
+  buffer->db= server->db ? strdup_root(mem, server->db) : NULL;
+  buffer->scheme= server->scheme ? strdup_root(mem, server->scheme) : NULL;
+  buffer->username= server->username? strdup_root(mem, server->username): NULL;
+  buffer->password= server->password? strdup_root(mem, server->password): NULL;
+  buffer->socket= server->socket ? strdup_root(mem, server->socket) : NULL;
+  buffer->owner= server->owner ? strdup_root(mem, server->owner) : NULL;
+  buffer->host= server->host ? strdup_root(mem, server->host) : NULL;
+
+ DBUG_RETURN(buffer);
+}
+
 
 /*
 
@@ -1199,11 +1241,11 @@
 
 */
 
-FOREIGN_SERVER *get_server_by_name(const char *server_name)
+FOREIGN_SERVER *get_server_by_name(MEM_ROOT *mem, const char *server_name,
+                                   FOREIGN_SERVER *buff)
 {
-  ulong error_num=0;
   uint server_name_length;
-  FOREIGN_SERVER *server= 0;
+  FOREIGN_SERVER *server;
   DBUG_ENTER("get_server_by_name");
   DBUG_PRINT("info", ("server_name %s", server_name));
 
@@ -1212,12 +1254,11 @@
   if (! server_name || !strlen(server_name))
   {
     DBUG_PRINT("info", ("server_name not defined!"));
-    error_num= 1;
     DBUG_RETURN((FOREIGN_SERVER *)NULL);
   }
 
   DBUG_PRINT("info", ("locking servers_cache"));
-  VOID(pthread_mutex_lock(&servers_cache_mutex));
+  rw_rdlock(&THR_LOCK_servers);
   if (!(server= (FOREIGN_SERVER *) hash_search(&servers_cache,
                                                (byte*) server_name,
                                                server_name_length)))
@@ -1226,8 +1267,12 @@
                         server_name, server_name_length));
     server= (FOREIGN_SERVER *) NULL;
   }
+  /* otherwise, make copy of server */
+  else
+    server= clone_server(mem, server, buff);
+
   DBUG_PRINT("info", ("unlocking servers_cache"));
-  VOID(pthread_mutex_unlock(&servers_cache_mutex));
+  rw_unlock(&THR_LOCK_servers);
   DBUG_RETURN(server);
 
 }

--- 1.105/mysql-test/r/ps.result	2007-03-27 22:15:46 +04:00
+++ 1.106/mysql-test/r/ps.result	2007-04-03 14:29:58 +04:00
@@ -1968,11 +1968,11 @@
 deallocate prepare abc;
 create procedure proc_1() show events;
 call proc_1();
-Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
+Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status	Originator
 call proc_1();
-Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
+Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status	Originator
 call proc_1();
-Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
+Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status	Originator
 drop procedure proc_1;
 create function func_1() returns int begin show events; return 1; end|
 ERROR 0A000: Not allowed to return a result set from a function
@@ -1982,11 +1982,11 @@
 ERROR 42000: FUNCTION test.func_1 does not exist
 prepare abc from "show events";
 execute abc;
-Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
+Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status	Originator
 execute abc;
-Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
+Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status	Originator
 execute abc;
-Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status
+Db	Name	Definer	Time zone	Type	Execute at	Interval value	Interval field	Starts	Ends	Status	Originator
 deallocate prepare abc;
 drop procedure if exists a;
 create procedure a() select 42;
Thread
bk commit into 5.1 tree (kostja:1.2551)konstantin3 Apr