MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:konstantin Date:March 19 2007 9:42pm
Subject:bk commit into 5.1 tree (kostja:1.2505)
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-03-20 00:42:11+03:00, kostja@stripped +51 -0
  Merge bk-internal.mysql.com:/home/bk/mysql-5.1
  into  bodhi.local:/opt/local/work/mysql-5.1-runtime
  MERGE: 1.2454.1.17

  BitKeeper/deleted/.del-init_db.sql~a77d572c39d5a1f8@stripped, 2007-03-20 00:37:24+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.31.1.2

  BitKeeper/deleted/.del-init_db.sql~a77d572c39d5a1f8@stripped, 2007-03-20 00:37:24+03:00, kostja@stripped +0 -0
    Merge rename: mysql-test/lib/init_db.sql -> BitKeeper/deleted/.del-init_db.sql~a77d572c39d5a1f8

  BitKeeper/deleted/.del-mysql_create_system_tables.sh@stripped, 2007-03-20 00:37:24+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.47.1.2

  BitKeeper/deleted/.del-mysql_create_system_tables.sh@stripped, 2007-03-20 00:37:24+03:00, kostja@stripped +0 -0
    Merge rename: scripts/mysql_create_system_tables.sh -> BitKeeper/deleted/.del-mysql_create_system_tables.sh

  include/my_global.h@stripped, 2007-03-20 00:37:24+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.157.1.5

  mysql-test/mysql-test-run.pl@stripped, 2007-03-20 00:37:24+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.270.1.6

  mysql-test/r/events_scheduling.result@stripped, 2007-03-20 00:37:24+03:00, kostja@stripped +0 -1
    Auto merged
    MERGE: 1.7.1.1

  mysql-test/r/query_cache.result@stripped, 2007-03-20 00:37:25+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.84.1.1

  mysql-test/r/skip_grants.result@stripped, 2007-03-20 00:42:03+03:00, kostja@stripped +0 -0
    Manualmerge.
    MERGE: 1.9.1.1

  mysql-test/r/sp.result@stripped, 2007-03-20 00:42:03+03:00, kostja@stripped +0 -0
    Manualmerge.
    MERGE: 1.248.1.5

  mysql-test/r/view.result@stripped, 2007-03-20 00:37:25+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.210.1.3

  mysql-test/t/events_scheduling.test@stripped, 2007-03-20 00:37:25+03:00, kostja@stripped +0 -1
    Auto merged
    MERGE: 1.9.1.1

  mysql-test/t/grant_cache.test@stripped, 2007-03-20 00:37:25+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.17.1.1

  mysql-test/t/query_cache.test@stripped, 2007-03-20 00:37:25+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.65.1.1

  mysql-test/t/skip_grants.test@stripped, 2007-03-20 00:42:03+03:00, kostja@stripped +0 -1
    Manualmerge.
    MERGE: 1.11.1.1

  mysql-test/t/sp.test@stripped, 2007-03-20 00:42:03+03:00, kostja@stripped +0 -0
    Manualmerge.
    MERGE: 1.216.1.4

  mysql-test/t/view.test@stripped, 2007-03-20 00:37:25+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.189.1.2

  scripts/mysql_system_tables_fix.sql@stripped, 2007-03-20 00:37:25+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.54.1.2

  scripts/mysql_system_tables_fix.sql@stripped, 2007-03-20 00:37:24+03:00, kostja@stripped +0 -0
    Merge rename: scripts/mysql_fix_privilege_tables.sql -> scripts/mysql_system_tables_fix.sql

  sql/event_data_objects.cc@stripped, 2007-03-20 00:42:03+03:00, kostja@stripped +0 -1
    Manualmerge.
    MERGE: 1.86.1.2

  sql/event_db_repository.cc@stripped, 2007-03-20 00:37:25+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.21.1.1

  sql/event_queue.cc@stripped, 2007-03-20 00:37:25+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.25.1.2

  sql/field.cc@stripped, 2007-03-20 00:37:26+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.376.1.2

  sql/handler.cc@stripped, 2007-03-20 00:37:26+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.295.1.4

  sql/handler.h@stripped, 2007-03-20 00:37:26+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.252.1.1

  sql/item.cc@stripped, 2007-03-20 00:37:28+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.246.2.1

  sql/item.h@stripped, 2007-03-20 00:37:29+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.227.1.1

  sql/item_func.cc@stripped, 2007-03-20 00:37:29+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.363.1.1

  sql/item_subselect.cc@stripped, 2007-03-20 00:37:30+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.149.1.2

  sql/log_event.cc@stripped, 2007-03-20 00:37:30+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.266.1.10

  sql/mysql_priv.h@stripped, 2007-03-20 00:37:30+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.479.1.2

  sql/mysqld.cc@stripped, 2007-03-20 00:37:31+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.613.1.2

  sql/set_var.cc@stripped, 2007-03-20 00:37:31+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.215.1.5

  sql/share/errmsg.txt@stripped, 2007-03-20 00:37:37+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.141.2.2

  sql/sp.cc@stripped, 2007-03-20 00:37:31+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.138.1.2

  sql/sp_head.cc@stripped, 2007-03-20 00:37:32+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.256.1.3

  sql/sp_head.h@stripped, 2007-03-20 00:37:32+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.97.1.3

  sql/sql_base.cc@stripped, 2007-03-20 00:37:32+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.381.1.3

  sql/sql_class.cc@stripped, 2007-03-20 00:37:32+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.312.1.7

  sql/sql_class.h@stripped, 2007-03-20 00:37:33+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.339.1.7

  sql/sql_help.cc@stripped, 2007-03-20 00:37:33+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.54.1.2

  sql/sql_lex.cc@stripped, 2007-03-20 00:37:33+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.230.1.1

  sql/sql_lex.h@stripped, 2007-03-20 00:37:33+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.265.1.1

  sql/sql_parse.cc@stripped, 2007-03-20 00:37:33+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.635.1.2

  sql/sql_prepare.cc@stripped, 2007-03-20 00:37:34+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.202.1.1

  sql/sql_select.cc@stripped, 2007-03-20 00:37:34+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.492.2.3

  sql/sql_show.cc@stripped, 2007-03-20 00:37:35+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.394.1.3

  sql/sql_table.cc@stripped, 2007-03-20 00:37:35+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.393.1.1

  sql/sql_yacc.yy@stripped, 2007-03-20 00:37:36+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.549.2.3

  sql/table.cc@stripped, 2007-03-20 00:37:36+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.275.3.2

  sql/tztime.cc@stripped, 2007-03-20 00:37:37+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.47.4.1

  storage/innobase/handler/ha_innodb.cc@stripped, 2007-03-20 00:37:38+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.320.2.1

  storage/myisam/ha_myisam.cc@stripped, 2007-03-20 00:37:38+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.209.1.2

  storage/myisam/ha_myisam.h@stripped, 2007-03-20 00:37:38+03:00, kostja@stripped +0 -0
    Auto merged
    MERGE: 1.81.1.1

# 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.380/sql/field.cc	2007-03-14 17:42:49 +03:00
+++ 1.381/sql/field.cc	2007-03-20 00:37:26 +03:00
@@ -1208,13 +1208,13 @@
 {
   ASSERT_COLUMN_MARKED_FOR_READ;
   CHARSET_INFO *cs= &my_charset_bin;
-  uint length= 21;
+  uint length;
   longlong value= val_int();
 
-  if (val_buffer->alloc(length))
+  if (val_buffer->alloc(MY_INT64_NUM_DECIMAL_DIGITS))
     return 0;
   length= (uint) (*cs->cset->longlong10_to_str)(cs, (char*) val_buffer->ptr(),
-                                                length,
+                                                MY_INT64_NUM_DECIMAL_DIGITS,
                                                 unsigned_val ? 10 : -10,
                                                 value);
   val_buffer->length(length);

--- 1.214/storage/myisam/ha_myisam.cc	2007-03-17 02:13:20 +03:00
+++ 1.215/storage/myisam/ha_myisam.cc	2007-03-20 00:37:38 +03:00
@@ -600,7 +600,8 @@
 
 bool ha_myisam::check_if_locking_is_allowed(uint sql_command,
                                             ulong type, TABLE *table,
-                                            uint count,
+                                            uint count, uint current,
+                                            uint *system_count,
                                             bool called_by_privileged_thread)
 {
   /*
@@ -609,11 +610,13 @@
     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 &&
-      count != 1)
+      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), table->s->db.str,
-             table->s->table_name.str);
+    my_error(ER_WRONG_LOCK_OF_SYSTEM_TABLE, MYF(0));
     return FALSE;
   }
 

--- 1.83/storage/myisam/ha_myisam.h	2007-03-17 02:13:20 +03:00
+++ 1.84/storage/myisam/ha_myisam.h	2007-03-20 00:37:38 +03:00
@@ -62,7 +62,8 @@
 
   virtual bool check_if_locking_is_allowed(uint sql_command,
                                            ulong type, TABLE *table,
-                                           uint count,
+                                           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);

--- 1.299/sql/handler.cc	2007-03-17 02:13:17 +03:00
+++ 1.300/sql/handler.cc	2007-03-20 00:37:26 +03:00
@@ -1143,9 +1143,9 @@
   XID_STATE *xs;
   DBUG_ENTER("mysql_xa_recover");
 
-  field_list.push_back(new Item_int("formatID",0,11));
-  field_list.push_back(new Item_int("gtrid_length",0,11));
-  field_list.push_back(new Item_int("bqual_length",0,11));
+  field_list.push_back(new Item_int("formatID", 0, MY_INT32_NUM_DECIMAL_DIGITS));
+  field_list.push_back(new Item_int("gtrid_length", 0, MY_INT32_NUM_DECIMAL_DIGITS));
+  field_list.push_back(new Item_int("bqual_length", 0, MY_INT32_NUM_DECIMAL_DIGITS));
   field_list.push_back(new Item_empty_string("data",XIDDATASIZE));
 
   if (protocol->send_fields(&field_list,

--- 1.254/sql/handler.h	2007-03-17 02:13:17 +03:00
+++ 1.255/sql/handler.h	2007-03-20 00:37:26 +03:00
@@ -986,7 +986,11 @@
       check_if_locking_is_allowed()
         thd     Handler of the thread, trying to lock the table
         table   Table handler to check
-        count   Number of locks already granted to the table
+        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
@@ -1005,7 +1009,8 @@
   */
   virtual bool check_if_locking_is_allowed(uint sql_command,
                                            ulong type, TABLE *table,
-                                           uint count,
+                                           uint count, uint current,
+                                           uint *system_count,
                                            bool called_by_privileged_thread)
   {
     return TRUE;

--- 1.255/sql/item.cc	2007-03-14 17:42:50 +03:00
+++ 1.256/sql/item.cc	2007-03-20 00:37:28 +03:00
@@ -148,7 +148,7 @@
 Hybrid_type_traits_integer::fix_length_and_dec(Item *item, Item *arg) const
 {
   item->decimals= 0;
-  item->max_length= 21;
+  item->max_length= MY_INT64_NUM_DECIMAL_DIGITS;
   item->unsigned_flag= 0;
 }
 
@@ -2525,7 +2525,7 @@
       item_result_type= REAL_RESULT;
       break;
     case INT_RESULT:
-      set_int(*(longlong*)entry->value, 21);
+      set_int(*(longlong*)entry->value, MY_INT64_NUM_DECIMAL_DIGITS);
       item_type= Item::INT_ITEM;
       item_result_type= INT_RESULT;
       break;
@@ -6676,7 +6676,7 @@
   case MYSQL_TYPE_SHORT:
     return 6;
   case MYSQL_TYPE_LONG:
-    return 11;
+    return MY_INT32_NUM_DECIMAL_DIGITS;
   case MYSQL_TYPE_FLOAT:
     return 25;
   case MYSQL_TYPE_DOUBLE:

--- 1.230/sql/item.h	2007-03-14 17:42:50 +03:00
+++ 1.231/sql/item.h	2007-03-20 00:37:29 +03:00
@@ -1592,11 +1592,14 @@
 {
 public:
   longlong value;
-  Item_int(int32 i,uint length=11) :value((longlong) i)
+  Item_int(int32 i,uint length= MY_INT32_NUM_DECIMAL_DIGITS)
+    :value((longlong) i)
     { max_length=length; fixed= 1; }
-  Item_int(longlong i,uint length=21) :value(i)
+  Item_int(longlong i,uint length= MY_INT64_NUM_DECIMAL_DIGITS)
+    :value(i)
     { max_length=length; fixed= 1; }
-  Item_int(ulonglong i, uint length= 21) :value((longlong)i)
+  Item_int(ulonglong i, uint length= MY_INT64_NUM_DECIMAL_DIGITS)
+    :value((longlong)i)
     { max_length=length; fixed= 1; unsigned_flag= 1; }
   Item_int(const char *str_arg,longlong i,uint length) :value(i)
     { max_length=length; name=(char*) str_arg; fixed= 1; }

--- 1.365/sql/item_func.cc	2007-03-09 12:39:37 +03:00
+++ 1.366/sql/item_func.cc	2007-03-20 00:37:29 +03:00
@@ -435,7 +435,7 @@
 
   switch (result_type()) {
   case INT_RESULT:
-    if (max_length > 11)
+    if (max_length > MY_INT32_NUM_DECIMAL_DIGITS)
       field= new Field_longlong(max_length, maybe_null, name, unsigned_flag);
     else
       field= new Field_long(max_length, maybe_null, name, unsigned_flag);
@@ -2338,7 +2338,8 @@
 
 void Item_func_locate::fix_length_and_dec()
 {
-  maybe_null=0; max_length=11;
+  maybe_null= 0;
+  max_length= MY_INT32_NUM_DECIMAL_DIGITS;
   agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV, 1);
 }
 

--- 1.270/sql/log_event.cc	2007-03-17 02:13:17 +03:00
+++ 1.271/sql/log_event.cc	2007-03-20 00:37:30 +03:00
@@ -642,12 +642,13 @@
 void Log_event::init_show_field_list(List<Item>* field_list)
 {
   field_list->push_back(new Item_empty_string("Log_name", 20));
-  field_list->push_back(new Item_return_int("Pos", 11,
+  field_list->push_back(new Item_return_int("Pos", MY_INT32_NUM_DECIMAL_DIGITS,
 					    MYSQL_TYPE_LONGLONG));
   field_list->push_back(new Item_empty_string("Event_type", 20));
   field_list->push_back(new Item_return_int("Server_id", 10,
 					    MYSQL_TYPE_LONG));
-  field_list->push_back(new Item_return_int("End_log_pos", 11,
+  field_list->push_back(new Item_return_int("End_log_pos",
+                                            MY_INT32_NUM_DECIMAL_DIGITS,
 					    MYSQL_TYPE_LONGLONG));
   field_list->push_back(new Item_empty_string("Info", 20));
 }
@@ -2006,8 +2007,7 @@
       if (time_zone_len)
       {
         String tmp(time_zone_str, time_zone_len, &my_charset_bin);
-        if (!(thd->variables.time_zone=
-              my_tz_find_with_opening_tz_tables(thd, &tmp)))
+        if (!(thd->variables.time_zone= my_tz_find(thd, &tmp)))
         {
           my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), tmp.c_ptr());
           thd->variables.time_zone= global_system_variables.time_zone;

--- 1.489/sql/mysql_priv.h	2007-03-17 02:13:17 +03:00
+++ 1.490/sql/mysql_priv.h	2007-03-20 00:37:30 +03:00
@@ -646,6 +646,7 @@
 {
   unsigned int client_long_flag:1;
   unsigned int client_protocol_41:1;
+  unsigned int result_in_binary_protocol:1;
   unsigned int more_results_exists:1;
   unsigned int pkt_nr;
   uint character_set_client_num;
@@ -672,6 +673,11 @@
   query_cache.send_result_to_client(A, B, C)
 #define query_cache_invalidate_by_MyISAM_filename_ref \
   &query_cache_invalidate_by_MyISAM_filename
+/* note the "maybe": it's a read without mutex */
+#define query_cache_maybe_disabled(T)                                 \
+  (T->variables.query_cache_type == 0 || query_cache.query_cache_size == 0)
+#define query_cache_is_cacheable_query(L) \
+  (((L)->sql_command == SQLCOM_SELECT) && (L)->safe_to_cache_query)
 #else
 #define QUERY_CACHE_FLAGS_SIZE 0
 #define query_cache_store_query(A, B)
@@ -688,6 +694,8 @@
 #define query_cache_abort(A)
 #define query_cache_end_of_result(A)
 #define query_cache_invalidate_by_MyISAM_filename_ref NULL
+#define query_cache_maybe_disabled(T) 1
+#define query_cache_is_cacheable_query(L) 0
 #endif /*HAVE_QUERY_CACHE*/
 
 /*
@@ -1428,6 +1436,12 @@
 int abort_and_upgrade_lock(ALTER_PARTITION_PARAM_TYPE *lpt);
 void close_open_tables_and_downgrade(ALTER_PARTITION_PARAM_TYPE *lpt);
 void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table);
+
+/* Functions to work with system tables. */
+bool open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
+                                 Open_tables_state *backup);
+void close_system_tables(THD *thd, Open_tables_state *backup);
+TABLE *open_system_table_for_update(THD *thd, TABLE_LIST *one_table);
 
 bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables, bool have_lock = FALSE);
 void copy_field_from_tmp_record(Field *field,int offset);

--- 1.621/sql/mysqld.cc	2007-03-16 10:54:33 +03:00
+++ 1.622/sql/mysqld.cc	2007-03-20 00:37:31 +03:00
@@ -3805,6 +3805,7 @@
     udf_init();
 #endif
   }
+
   init_status_vars();
   if (opt_bootstrap) /* If running with bootstrap, do not start replication. */
     opt_skip_slave_start= 1;
@@ -3850,6 +3851,10 @@
   {
     if (Events::get_instance()->init())
       unireg_abort(1);
+  }
+  else
+  {
+    Events::opt_event_scheduler = Events::EVENTS_DISABLED; 
   }
 
   /* Signal threads waiting for server to be started */

--- 1.386/sql/sql_base.cc	2007-03-09 18:54:11 +03:00
+++ 1.387/sql/sql_base.cc	2007-03-20 00:37:32 +03:00
@@ -5503,7 +5503,8 @@
 
           Item_int do not need fix_fields() because it is basic constant.
         */
-        it.replace(new Item_int("Not_used", (longlong) 1, 21));
+        it.replace(new Item_int("Not_used", (longlong) 1,
+                                MY_INT64_NUM_DECIMAL_DIGITS));
       }
       else if (insert_fields(thd, ((Item_field*) item)->context,
                              ((Item_field*) item)->db_name,
@@ -6877,4 +6878,123 @@
     }
   }
   return 0;
+}
+
+
+/*
+  Open and lock system tables for read.
+
+  SYNOPSIS
+    open_system_tables_for_read()
+      thd         Thread context.
+      table_list  List of tables to open.
+      backup      Pointer to Open_tables_state instance where
+                  information about currently open tables will be
+                  saved, and from which will be restored when we will
+                  end work with system tables.
+
+  NOTES
+    Thanks to restrictions which we put on opening and locking of
+    system tables for writing, we can open and lock them for reading
+    even when we already have some other tables open and locked.  One
+    must call close_system_tables() to close systems tables opened
+    with this call.
+
+  RETURN
+    FALSE   Success
+    TRUE    Error
+*/
+
+bool
+open_system_tables_for_read(THD *thd, TABLE_LIST *table_list,
+                            Open_tables_state *backup)
+{
+  DBUG_ENTER("open_system_tables_for_read");
+
+  thd->reset_n_backup_open_tables_state(backup);
+
+  uint count= 0;
+  bool not_used;
+  for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global)
+  {
+    TABLE *table= open_table(thd, tables, thd->mem_root, &not_used,
+                             MYSQL_LOCK_IGNORE_FLUSH);
+    if (!table)
+      goto error;
+
+    DBUG_ASSERT(table->s->system_table);
+
+    table->use_all_columns();
+    table->reginfo.lock_type= tables->lock_type;
+    tables->table= table;
+    count++;
+  }
+
+  {
+    TABLE **list= (TABLE**) thd->alloc(sizeof(TABLE*) * count);
+    TABLE **ptr= list;
+    for (TABLE_LIST *tables= table_list; tables; tables= tables->next_global)
+      *(ptr++)= tables->table;
+
+    thd->lock= mysql_lock_tables(thd, list, count,
+                                 MYSQL_LOCK_IGNORE_FLUSH, &not_used);
+  }
+  if (thd->lock)
+    DBUG_RETURN(FALSE);
+
+error:
+  close_system_tables(thd, backup);
+
+  DBUG_RETURN(TRUE);
+}
+
+
+/*
+  Close system tables, opened with open_system_tables_for_read().
+
+  SYNOPSIS
+    close_system_tables()
+      thd     Thread context
+      backup  Pointer to Open_tables_state instance which holds
+              information about tables which were open before we
+              decided to access system tables.
+*/
+
+void
+close_system_tables(THD *thd, Open_tables_state *backup)
+{
+  close_thread_tables(thd);
+  thd->restore_backup_open_tables_state(backup);
+}
+
+
+/*
+  Open and lock one system table for update.
+
+  SYNOPSIS
+    open_system_table_for_update()
+      thd        Thread context.
+      one_table  Table to open.
+
+  NOTES
+    Table opened with this call should closed using close_thread_tables().
+
+  RETURN
+    0	Error
+    #	Pointer to TABLE object of system table
+*/
+
+TABLE *
+open_system_table_for_update(THD *thd, TABLE_LIST *one_table)
+{
+  DBUG_ENTER("open_system_table_for_update");
+
+  TABLE *table= open_ltable(thd, one_table, one_table->lock_type);
+  if (table)
+  {
+    DBUG_ASSERT(table->s->system_table);
+    table->use_all_columns();
+  }
+
+  DBUG_RETURN(table);
 }

--- 1.319/sql/sql_class.cc	2007-03-08 04:05:03 +03:00
+++ 1.320/sql/sql_class.cc	2007-03-20 00:37:32 +03:00
@@ -303,9 +303,9 @@
     bzero((char*) &user_var_events, sizeof(user_var_events));
 
   /* Protocol */
-  protocol= &protocol_simple;			// Default protocol
-  protocol_simple.init(this);
-  protocol_prep.init(this);
+  protocol= &protocol_text;			// Default protocol
+  protocol_text.init(this);
+  protocol_binary.init(this);
 
   tablespace_op=FALSE;
   tmp= sql_rnd_with_mutex();

--- 1.347/sql/sql_class.h	2007-03-16 00:14:54 +03:00
+++ 1.348/sql/sql_class.h	2007-03-20 00:37:33 +03:00
@@ -910,8 +910,8 @@
   NET	  net;				// client connection descriptor
   MEM_ROOT warn_root;			// For warnings and errors
   Protocol *protocol;			// Current protocol
-  Protocol_simple protocol_simple;	// Normal protocol
-  Protocol_prep protocol_prep;		// Binary protocol
+  Protocol_text   protocol_text;	// Normal protocol
+  Protocol_binary protocol_binary;	// Binary protocol
   HASH    user_vars;			// hash for user variables
   String  packet;			// dynamic buffer for network I/O
   String  convert_buffer;               // buffer for charset conversions

--- 1.233/sql/sql_lex.cc	2007-03-09 17:55:58 +03:00
+++ 1.234/sql/sql_lex.cc	2007-03-20 00:37:33 +03:00
@@ -169,7 +169,6 @@
   lex->lock_option= TL_READ;
   lex->found_semicolon= 0;
   lex->safe_to_cache_query= 1;
-  lex->time_zone_tables_used= 0;
   lex->leaf_tables_insert= 0;
   lex->parsing_options.reset();
   lex->empty_field_list_on_rset= 0;
@@ -2087,31 +2086,6 @@
 
 
 /*
-  Add implicitly used time zone description tables to global table list
-  (if needed).
-
-  SYNOPSYS
-    st_lex::add_time_zone_tables_to_query_tables()
-      thd - pointer to current thread context
-
-  RETURN VALUE
-   TRUE  - error
-   FALSE - success
-*/
-
-bool st_lex::add_time_zone_tables_to_query_tables(THD *thd_arg)
-{
-  /* We should not add these tables twice */
-  if (!time_zone_tables_used)
-  {
-    time_zone_tables_used= my_tz_get_table_list(thd_arg, &query_tables_last);
-    if (time_zone_tables_used == &fake_time_zone_tables_list)
-      return TRUE;
-  }
-  return FALSE;
-}
-
-/*
   Link table back that was unlinked with unlink_first_table()
 
   SYNOPSIS
@@ -2180,7 +2154,6 @@
     /* remove underlying units (units of VIEW) subtree */
     select_lex.cut_subtree();
   }
-  time_zone_tables_used= 0;
 }
 
 

--- 1.268/sql/sql_lex.h	2007-03-09 17:55:58 +03:00
+++ 1.269/sql/sql_lex.h	2007-03-20 00:37:33 +03:00
@@ -1155,11 +1155,6 @@
   bool prepared_stmt_code_is_varref;
   /* Names of user variables holding parameters (in EXECUTE) */
   List<LEX_STRING> prepared_stmt_params;
-  /*
-    Points to part of global table list which contains time zone tables
-    implicitly used by the statement.
-  */
-  TABLE_LIST *time_zone_tables_used;
   sp_head *sphead;
   sp_name *spname;
   bool sp_lex_in_use;	/* Keep track on lex usage in SPs for error handling */
@@ -1246,7 +1241,6 @@
   TABLE_LIST *unlink_first_table(bool *link_to_local);
   void link_first_table_back(TABLE_LIST *first, bool link_to_local);
   void first_lists_tables_same();
-  bool add_time_zone_tables_to_query_tables(THD *thd);
 
   bool can_be_merged();
   bool can_use_merged();

--- 1.647/sql/sql_parse.cc	2007-03-16 10:56:26 +03:00
+++ 1.648/sql/sql_parse.cc	2007-03-20 00:37:33 +03:00
@@ -1689,8 +1689,7 @@
     Don't reset warnings when executing a stored routine.
   */
   if ((all_tables || &lex->select_lex != lex->all_selects_list ||
-       lex->sroutines.records) && !thd->spcont ||
-      lex->time_zone_tables_used)
+       lex->sroutines.records) && !thd->spcont)
     mysql_reset_errors(thd, 0);
 
 #ifdef HAVE_REPLICATION
@@ -4739,9 +4738,7 @@
      */
     tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
     if (tables->derived || tables->schema_table ||
-        (tables->table && (int)tables->table->s->tmp_table) ||
-        my_tz_check_n_skip_implicit_tables(&tables,
-                                           thd->lex->time_zone_tables_used))
+        (tables->table && (int)tables->table->s->tmp_table))
       continue;
     thd->security_ctx= sctx;
     if ((sctx->master_access & want_access) ==
@@ -6503,14 +6500,12 @@
   /*
     Is there tables of subqueries?
   */
-  if (&lex->select_lex != lex->all_selects_list || lex->time_zone_tables_used)
+  if (&lex->select_lex != lex->all_selects_list)
   {
     DBUG_PRINT("info",("Checking sub query list"));
     for (table= tables; table; table= table->next_global)
     {
-      if (!my_tz_check_n_skip_implicit_tables(&table,
-                                              lex->time_zone_tables_used) &&
-          !table->table_in_first_from_clause)
+      if (!table->table_in_first_from_clause)
       {
 	if (check_access(thd, SELECT_ACL, table->db,
 			 &table->grant.privilege, 0, 0,

--- 1.498/sql/sql_select.cc	2007-03-17 02:13:18 +03:00
+++ 1.499/sql/sql_select.cc	2007-03-20 00:37:34 +03:00
@@ -8193,9 +8193,14 @@
 	*/ 
         expr= simplify_joins(join, &nested_join->join_list,
                              expr, FALSE);
-        table->on_expr= expr;
-        if (!table->prep_on_expr)
+
+        if (!table->prep_on_expr || expr != table->on_expr)
+        {
+          DBUG_ASSERT(expr);
+
+          table->on_expr= expr;
           table->prep_on_expr= expr->copy_andor_structure(join->thd);
+        }
       }
       nested_join->used_tables= (table_map) 0;
       nested_join->not_null_tables=(table_map) 0;
@@ -8205,7 +8210,7 @@
     }
     else
     {
-      if (!(table->prep_on_expr))
+      if (!table->prep_on_expr)
         table->prep_on_expr= table->on_expr;
       used_tables= table->table->map;
       if (conds)
@@ -8697,7 +8702,7 @@
 	if ((new_cond= new Item_func_eq(args[0],
 					new Item_int("last_insert_id()",
                                                      thd->read_first_successful_insert_id_in_prev_stmt(),
-						     21))))
+                                                     MY_INT64_NUM_DECIMAL_DIGITS))))
 	{
 	  cond=new_cond;
           /*
@@ -8962,7 +8967,7 @@
     break;
   case INT_RESULT:
     /* Select an integer type with the minimal fit precision */
-    if (item->max_length > 11)
+    if (item->max_length > MY_INT32_NUM_DECIMAL_DIGITS)
       new_field=new Field_longlong(item->max_length, maybe_null,
                                    item->name, item->unsigned_flag);
     else
@@ -15277,7 +15282,7 @@
         examined_rows=(ha_rows)join->best_positions[i].records_read; 
  
       item_list.push_back(new Item_int((longlong) (ulonglong) examined_rows, 
-                                       21));
+                                       MY_INT64_NUM_DECIMAL_DIGITS));
 
       /* Add "filtered" field to item_list. */
       if (join->thd->lex->describe & DESCRIBE_EXTENDED)

--- 1.398/sql/sql_show.cc	2007-03-14 17:42:50 +03:00
+++ 1.399/sql/sql_show.cc	2007-03-20 00:37:35 +03:00
@@ -38,6 +38,7 @@
   ISE_EVENT_SCHEMA,
   ISE_EVENT_NAME,
   ISE_DEFINER,
+  ISE_TIME_ZONE,
   ISE_EVENT_BODY,
   ISE_EVENT_DEFINITION,
   ISE_EVENT_TYPE,
@@ -424,7 +425,8 @@
   DBUG_ENTER("mysqld_show_column_types");
 
   field_list.push_back(new Item_empty_string("Type",30));
-  field_list.push_back(new Item_int("Size",(longlong) 1,21));
+  field_list.push_back(new Item_int("Size",(longlong) 1,
+                                    MY_INT64_NUM_DECIMAL_DIGITS));
   field_list.push_back(new Item_empty_string("Min_Value",20));
   field_list.push_back(new Item_empty_string("Max_Value",20));
   field_list.push_back(new Item_return_int("Prec", 4, MYSQL_TYPE_SHORT));
@@ -1620,7 +1622,7 @@
   Protocol *protocol= thd->protocol;
   DBUG_ENTER("mysqld_list_processes");
 
-  field_list.push_back(new Item_int("Id",0,11));
+  field_list.push_back(new Item_int("Id", 0, MY_INT32_NUM_DECIMAL_DIGITS));
   field_list.push_back(new Item_empty_string("User",16));
   field_list.push_back(new Item_empty_string("Host",LIST_PROCESS_HOST_LEN));
   field_list.push_back(field=new Item_empty_string("db",NAME_LEN));
@@ -3510,7 +3512,7 @@
 
 err:
   proc_table->file->ha_index_end();
-  close_proc_table(thd, &open_tables_state_backup);
+  close_system_tables(thd, &open_tables_state_backup);
   DBUG_RETURN(res);
 }
 
@@ -4309,7 +4311,7 @@
 
   restore_record(sch_table, s->default_values);
 
-  if (et.load_from_row(event_table))
+  if (et.load_from_row(thd, event_table))
   {
     my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0));
     DBUG_RETURN(1);
@@ -4336,6 +4338,9 @@
                                 store(et.name.str, et.name.length, scs);
   sch_table->field[ISE_DEFINER]->
                                 store(et.definer.str, et.definer.length, scs);
+  const String *tz_name= et.time_zone->get_name();
+  sch_table->field[ISE_TIME_ZONE]->
+                                store(tz_name->ptr(), tz_name->length(), scs);
   sch_table->field[ISE_EVENT_BODY]->
                                 store(STRING_WITH_LEN("SQL"), scs);
   sch_table->field[ISE_EVENT_DEFINITION]->
@@ -4352,6 +4357,8 @@
                                 store((const char*)sql_mode_str, sql_mode_len, scs);
   }
 
+  int not_used=0;
+
   if (et.expression)
   {
     String show_str;
@@ -4371,15 +4378,17 @@
     sch_table->field[ISE_INTERVAL_FIELD]->store(ival->str, ival->length, scs);
 
     /* starts & ends . STARTS is always set - see sql_yacc.yy */
+    et.time_zone->gmt_sec_to_TIME(&time, et.starts);
     sch_table->field[ISE_STARTS]->set_notnull();
     sch_table->field[ISE_STARTS]->
-                                store_time(&et.starts, MYSQL_TIMESTAMP_DATETIME);
+                                store_time(&time, MYSQL_TIMESTAMP_DATETIME);
 
     if (!et.ends_null)
     {
+      et.time_zone->gmt_sec_to_TIME(&time, et.ends);
       sch_table->field[ISE_ENDS]->set_notnull();
       sch_table->field[ISE_ENDS]->
-                                store_time(&et.ends, MYSQL_TIMESTAMP_DATETIME);
+                                store_time(&time, MYSQL_TIMESTAMP_DATETIME);
     }
   }
   else
@@ -4387,9 +4396,10 @@
     /* type */
     sch_table->field[ISE_EVENT_TYPE]->store(STRING_WITH_LEN("ONE TIME"), scs);
 
+    et.time_zone->gmt_sec_to_TIME(&time, et.execute_at);
     sch_table->field[ISE_EXECUTE_AT]->set_notnull();
     sch_table->field[ISE_EXECUTE_AT]->
-                          store_time(&et.execute_at, MYSQL_TIMESTAMP_DATETIME);
+                          store_time(&time, MYSQL_TIMESTAMP_DATETIME);
   }
 
   /* status */
@@ -4406,7 +4416,6 @@
     sch_table->field[ISE_ON_COMPLETION]->
                                 store(STRING_WITH_LEN("PRESERVE"), scs);
     
-  int not_used=0;
   number_to_datetime(et.created, &time, 0, &not_used);
   DBUG_ASSERT(not_used==0);
   sch_table->field[ISE_CREATED]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
@@ -4416,11 +4425,12 @@
   sch_table->field[ISE_LAST_ALTERED]->
                                 store_time(&time, MYSQL_TIMESTAMP_DATETIME);
 
-  if (et.last_executed.year)
+  if (et.last_executed)
   {
+    et.time_zone->gmt_sec_to_TIME(&time, et.last_executed);
     sch_table->field[ISE_LAST_EXECUTED]->set_notnull();
     sch_table->field[ISE_LAST_EXECUTED]->
-                       store_time(&et.last_executed, MYSQL_TIMESTAMP_DATETIME);
+                       store_time(&time, MYSQL_TIMESTAMP_DATETIME);
   }
 
   sch_table->field[ISE_EVENT_COMMENT]->
@@ -5334,20 +5344,25 @@
   {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
   {"TABLE_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
   {"ENGINE", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, "Engine"},
-  {"VERSION", 21 , MYSQL_TYPE_LONG, 0, 1, "Version"},
+  {"VERSION", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, "Version"},
   {"ROW_FORMAT", 10, MYSQL_TYPE_STRING, 0, 1, "Row_format"},
-  {"TABLE_ROWS", 21 , MYSQL_TYPE_LONG, 0, 1, "Rows"},
-  {"AVG_ROW_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Avg_row_length"},
-  {"DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_length"},
-  {"MAX_DATA_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Max_data_length"},
-  {"INDEX_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, "Index_length"},
-  {"DATA_FREE", 21 , MYSQL_TYPE_LONG, 0, 1, "Data_free"},
-  {"AUTO_INCREMENT", 21 , MYSQL_TYPE_LONG, 0, 1, "Auto_increment"},
+  {"TABLE_ROWS", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, "Rows"},
+  {"AVG_ROW_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
+   "Avg_row_length"},
+  {"DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
+   "Data_length"},
+  {"MAX_DATA_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
+   "Max_data_length"},
+  {"INDEX_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
+   "Index_length"},
+  {"DATA_FREE", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, "Data_free"},
+  {"AUTO_INCREMENT", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
+   "Auto_increment"},
   {"CREATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Create_time"},
   {"UPDATE_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Update_time"},
   {"CHECK_TIME", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Check_time"},
   {"TABLE_COLLATION", 64, MYSQL_TYPE_STRING, 0, 1, "Collation"},
-  {"CHECKSUM", 21 , MYSQL_TYPE_LONG, 0, 1, "Checksum"},
+  {"CHECKSUM", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, "Checksum"},
   {"CREATE_OPTIONS", 255, MYSQL_TYPE_STRING, 0, 1, "Create_options"},
   {"TABLE_COMMENT", 80, MYSQL_TYPE_STRING, 0, 0, "Comment"},
   {0, 0, MYSQL_TYPE_STRING, 0, 0, 0}
@@ -5360,14 +5375,15 @@
   {"TABLE_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
   {"TABLE_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
   {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Field"},
-  {"ORDINAL_POSITION", 21 , MYSQL_TYPE_LONG, 0, 0, 0},
+  {"ORDINAL_POSITION", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 0, 0},
   {"COLUMN_DEFAULT", MAX_FIELD_VARCHARLENGTH, MYSQL_TYPE_STRING, 0, 1, "Default"},
   {"IS_NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null"},
   {"DATA_TYPE", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0},
-  {"CHARACTER_MAXIMUM_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
-  {"CHARACTER_OCTET_LENGTH", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
-  {"NUMERIC_PRECISION", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
-  {"NUMERIC_SCALE", 21 , MYSQL_TYPE_LONG, 0, 1, 0},
+  {"CHARACTER_MAXIMUM_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1,
+   0},
+  {"CHARACTER_OCTET_LENGTH", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, 0},
+  {"NUMERIC_PRECISION", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, 0},
+  {"NUMERIC_SCALE", MY_INT64_NUM_DECIMAL_DIGITS , MYSQL_TYPE_LONG, 0, 1, 0},
   {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 1, 0},
   {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 1, "Collation"},
   {"COLUMN_TYPE", 65535, MYSQL_TYPE_STRING, 0, 0, "Type"},
@@ -5393,7 +5409,7 @@
 {
   {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Collation"},
   {"CHARACTER_SET_NAME", 64, MYSQL_TYPE_STRING, 0, 0, "Charset"},
-  {"ID", 11, MYSQL_TYPE_LONG, 0, 0, "Id"},
+  {"ID", MY_INT32_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 0, "Id"},
   {"IS_DEFAULT", 3, MYSQL_TYPE_STRING, 0, 0, "Default"},
   {"IS_COMPILED", 3, MYSQL_TYPE_STRING, 0, 0, "Compiled"},
   {"SORTLEN", 3 ,MYSQL_TYPE_LONG, 0, 0, "Sortlen"},
@@ -5419,6 +5435,7 @@
   {"EVENT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Db"},
   {"EVENT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"},
   {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer"},
+  {"TIME_ZONE", 64, MYSQL_TYPE_STRING, 0, 0, "Time zone"},
   {"EVENT_BODY", 8, MYSQL_TYPE_STRING, 0, 0, 0},
   {"EVENT_DEFINITION", 65535, MYSQL_TYPE_STRING, 0, 0, 0},
   {"EVENT_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type"},
@@ -5484,7 +5501,7 @@
   {"SEQ_IN_INDEX", 2, MYSQL_TYPE_LONG, 0, 0, "Seq_in_index"},
   {"COLUMN_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Column_name"},
   {"COLLATION", 1, MYSQL_TYPE_STRING, 0, 1, "Collation"},
-  {"CARDINALITY", 21, MYSQL_TYPE_LONG, 0, 1, "Cardinality"},
+  {"CARDINALITY", MY_INT64_NUM_DECIMAL_DIGITS, MYSQL_TYPE_LONG, 0, 1, "Cardinality"},
   {"SUB_PART", 3, MYSQL_TYPE_LONG, 0, 1, "Sub_part"},
   {"PACKED", 10, MYSQL_TYPE_STRING, 0, 1, "Packed"},
   {"NULLABLE", 3, MYSQL_TYPE_STRING, 0, 0, "Null"},

--- 1.397/sql/sql_table.cc	2007-03-14 18:07:47 +03:00
+++ 1.398/sql/sql_table.cc	2007-03-20 00:37:35 +03:00
@@ -6948,7 +6948,8 @@
 
   field_list.push_back(item = new Item_empty_string("Table", NAME_LEN*2));
   item->maybe_null= 1;
-  field_list.push_back(item=new Item_int("Checksum",(longlong) 1,21));
+  field_list.push_back(item= new Item_int("Checksum", (longlong) 1,
+                                          MY_INT64_NUM_DECIMAL_DIGITS));
   item->maybe_null= 1;
   if (protocol->send_fields(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))

--- 1.552/sql/sql_yacc.yy	2007-03-15 00:30:47 +03:00
+++ 1.553/sql/sql_yacc.yy	2007-03-20 00:37:36 +03:00
@@ -481,6 +481,7 @@
   struct st_lex *lex;
   sp_head *sphead;
   struct p_elem_val *p_elem_value;
+  enum index_hint_type index_hint;
 }
 
 %{
@@ -1162,7 +1163,7 @@
 	btree_or_rtree
 
 %type <string_list>
-	key_usage_list using_list
+	using_list
 
 %type <key_part>
 	key_part
@@ -1233,7 +1234,7 @@
 	opt_column_list grant_privileges grant_ident grant_list grant_option
 	object_privilege object_privilege_list user_list rename_list
 	clear_privileges flush_options flush_option
-	equal optional_braces opt_key_definition key_usage_list2
+	equal optional_braces
 	opt_mi_check_type opt_to mi_check_types normal_join
 	db_to_db table_to_table_list table_to_table opt_table_list opt_as
 	handler_rkey_function handler_read_or_scan
@@ -1269,6 +1270,8 @@
 %type <spblock> sp_decls sp_decl
 %type <lex> sp_cursor_stmt
 %type <spname> sp_name
+%type <index_hint> index_hint_type
+%type <num> index_hint_clause
 
 %type <NONE>
 	'-' '+' '*' '/' '%' '(' ')'
@@ -5936,12 +5939,8 @@
 assign_to_keycache:
         table_ident cache_keys_spec
         {
-          LEX *lex=Lex;
-          SELECT_LEX *sel= &lex->select_lex;
-          if (!sel->add_table_to_list(lex->thd, $1, NULL, 0,
-                                      TL_READ,
-                                      sel->get_use_index(),
-                                      (List<String> *)0))
+          if (!Select->add_table_to_list(YYTHD, $1, NULL, 0, TL_READ, 
+                                      Select->pop_index_hints()))
             MYSQL_YYABORT;
         }
         ;
@@ -5968,33 +5967,26 @@
 preload_keys:
 	table_ident cache_keys_spec opt_ignore_leaves
 	{
-	  LEX *lex=Lex;
-	  SELECT_LEX *sel= &lex->select_lex;
-	  if (!sel->add_table_to_list(lex->thd, $1, NULL, $3,
-                                      TL_READ,
-                                      sel->get_use_index(),
-                                      (List<String> *)0))
+	  if (!Select->add_table_to_list(YYTHD, $1, NULL, $3, TL_READ,
+                                      Select->pop_index_hints()))
             MYSQL_YYABORT;
 	}
 	;
 
 cache_keys_spec:
-        { Select->interval_list.empty(); }
-        cache_key_list_or_empty
-        {
-          LEX *lex=Lex;
-          SELECT_LEX *sel= &lex->select_lex;
-          sel->use_index= sel->interval_list;
+        { 
+          Lex->select_lex.alloc_index_hints(YYTHD);
+          Select->set_index_hint_type(INDEX_HINT_USE, 
+                                      global_system_variables.old_mode ? 
+                                        INDEX_HINT_MASK_JOIN : 
+                                        INDEX_HINT_MASK_ALL);
         }
+        cache_key_list_or_empty
         ;
 
 cache_key_list_or_empty:
-	/* empty */	{ Lex->select_lex.use_index_ptr= 0; }
-	| opt_key_or_index '(' key_usage_list2 ')'
-	  {
-            SELECT_LEX *sel= &Lex->select_lex;
-	    sel->use_index_ptr= &sel->use_index;
-	  }
+	/* empty */	{ }
+	| key_or_index '(' opt_key_usage_list ')'
 	;
 
 opt_ignore_leaves:
@@ -7367,20 +7359,16 @@
 table_factor:
 	{
 	  SELECT_LEX *sel= Select;
-	  sel->use_index_ptr=sel->ignore_index_ptr=0;
 	  sel->table_join_options= 0;
 	}
         table_ident opt_table_alias opt_key_definition
 	{
-	  LEX *lex= Lex;
-	  SELECT_LEX *sel= lex->current_select;
-	  if (!($$= sel->add_table_to_list(lex->thd, $2, $3,
-					   sel->get_table_join_options(),
-					   lex->lock_option,
-					   sel->get_use_index(),
-					   sel->get_ignore_index())))
+	  if (!($$= Select->add_table_to_list(YYTHD, $2, $3,
+					   Select->get_table_join_options(),
+					   Lex->lock_option,
+					   Select->pop_index_hints())))
 	    MYSQL_YYABORT;
-          sel->add_joined_table($$);
+          Select->add_joined_table($$);
 	}
 	| '{' ident table_ref LEFT OUTER JOIN_SYM table_ref
           ON
@@ -7449,8 +7437,7 @@
 	    lex->current_select= sel= unit->outer_select();
 	    if (!($$= sel->
                   add_table_to_list(lex->thd, new Table_ident(unit), $6, 0,
-				    TL_READ,(List<String> *)0,
-	                            (List<String> *)0)))
+				    TL_READ)))
 
 	      MYSQL_YYABORT;
             sel->add_joined_table($$);
@@ -7549,52 +7536,67 @@
 	/* empty */	{}
 	| OUTER		{};
 
+index_hint_clause:
+       /* empty */             
+         { 
+            $$= global_system_variables.old_mode ? 
+                  INDEX_HINT_MASK_JOIN : INDEX_HINT_MASK_ALL; 
+         } 
+       | FOR_SYM JOIN_SYM      { $$= INDEX_HINT_MASK_JOIN;  }
+       | FOR_SYM ORDER_SYM BY  { $$= INDEX_HINT_MASK_ORDER; }
+       | FOR_SYM GROUP_SYM BY  { $$= INDEX_HINT_MASK_GROUP; }
+       ;
+
+index_hint_type:
+       FORCE_SYM  { $$= INDEX_HINT_FORCE; }
+       | IGNORE_SYM { $$= INDEX_HINT_IGNORE; } 
+       ;
+
+index_hint_definition:
+       index_hint_type key_or_index index_hint_clause
+       {
+         Select->set_index_hint_type($1, $3);
+       }
+       '(' key_usage_list ')';
+       | USE_SYM key_or_index index_hint_clause
+       {
+         Select->set_index_hint_type(INDEX_HINT_USE, $3);
+       }
+       '(' opt_key_usage_list ')';
+
+
+index_hints_list:
+       index_hint_definition         
+       | index_hints_list index_hint_definition
+       ;
+
+opt_index_hints_list:
+       /* empty */
+       | { Select->alloc_index_hints(YYTHD); } index_hints_list
+       ;
+
 opt_key_definition:
-	/* empty */	{}
-	| USE_SYM    key_usage_list
-          {
-	    SELECT_LEX *sel= Select;
-	    sel->use_index= *$2;
-	    sel->use_index_ptr= &sel->use_index;
-	  }
-	| FORCE_SYM key_usage_list
-          {
-	    SELECT_LEX *sel= Select;
-	    sel->use_index= *$2;
-	    sel->use_index_ptr= &sel->use_index;
-	    sel->table_join_options|= TL_OPTION_FORCE_INDEX;
-	  }
-	| IGNORE_SYM key_usage_list
-	  {
-	    SELECT_LEX *sel= Select;
-	    sel->ignore_index= *$2;
-	    sel->ignore_index_ptr= &sel->ignore_index;
-	  };
+       {  Select->clear_index_hints(); }
+       opt_index_hints_list
+       ;
 
-key_usage_list:
-	key_or_index { Select->interval_list.empty(); }
-        '(' key_list_or_empty ')'
-        { $$= &Select->interval_list; }
+opt_key_usage_list:
+	/* empty */ 		{ Select->add_index_hint(YYTHD, NULL, 0); }
+	| key_usage_list	{}
 	;
 
-key_list_or_empty:
-	/* empty */ 		{}
-	| key_usage_list2	{}
-	;
+key_usage_element:
+	ident           { Select->add_index_hint(YYTHD, $1.str, $1.length); }
+	| PRIMARY_SYM   
+          { 
+            Select->add_index_hint(YYTHD, (char *)"PRIMARY", 7); 
+          }
+        ;
 
-key_usage_list2:
-	key_usage_list2 ',' ident
-        { Select->
-	    interval_list.push_back(new (YYTHD->mem_root) String((const char*) $3.str, $3.length,
-				    system_charset_info)); }
-	| ident
-        { Select->
-	    interval_list.push_back(new (YYTHD->mem_root) String((const char*) $1.str, $1.length,
-				    system_charset_info)); }
-	| PRIMARY_SYM
-        { Select->
-	    interval_list.push_back(new (YYTHD->mem_root) String("PRIMARY", 7,
-				    system_charset_info)); };
+key_usage_list:
+        key_usage_element
+	| key_usage_list ',' key_usage_element
+        ;
 
 using_list:
 	ident

--- 1.280/sql/table.cc	2007-03-17 02:13:19 +03:00
+++ 1.281/sql/table.cc	2007-03-20 00:37:36 +03:00
@@ -245,6 +245,50 @@
 }
 
 
+/**
+  Return TRUE if a table name matches one of the system table names.
+  Currently these are:
+
+  help_category, help_keyword, help_relation, help_topic,
+  proc,
+  time_zone, time_zone_leap_second, time_zone_name, time_zone_transition,
+  time_zone_transition_type
+
+  This function trades accuracy for speed, so may return false
+  positives. Presumably mysql.* database is for internal purposes only
+  and should not contain user tables.
+*/
+
+inline bool is_system_table_name(const char *name, uint length)
+{
+  CHARSET_INFO *ci= system_charset_info;
+
+  return (
+          /* mysql.proc table */
+          length == 4 &&
+          my_tolower(ci, name[0]) == 'p' && 
+          my_tolower(ci, name[1]) == 'r' &&
+          my_tolower(ci, name[2]) == 'o' &&
+          my_tolower(ci, name[3]) == 'c' ||
+
+          length > 4 &&
+          (
+           /* one of mysql.help* tables */
+           my_tolower(ci, name[0]) == 'h' &&
+           my_tolower(ci, name[1]) == 'e' &&
+           my_tolower(ci, name[2]) == 'l' &&
+           my_tolower(ci, name[3]) == 'p' ||
+
+           /* one of mysql.time_zone* tables */
+           my_tolower(ci, name[0]) == 't' &&
+           my_tolower(ci, name[1]) == 'i' &&
+           my_tolower(ci, name[2]) == 'm' &&
+           my_tolower(ci, name[3]) == 'e'
+          )
+         );
+}
+
+
 /*
   Read table definition from a binary / text based .frm file
   
@@ -365,11 +409,9 @@
         allow to lock such tables for writing with any other tables (even with
         other system tables) and some privilege tables need this.
       */
-      if (!(lower_case_table_names ?
-            my_strcasecmp(system_charset_info, share->table_name.str, "proc") :
-            strcmp(share->table_name.str, "proc")))
-        share->system_table= 1;
-      else
+      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,

--- 1.23/sql/event_db_repository.cc	2007-03-17 02:13:17 +03:00
+++ 1.24/sql/event_db_repository.cc	2007-03-20 00:37:25 +03:00
@@ -118,6 +118,11 @@
     { C_STRING_WITH_LEN("comment") },
     { C_STRING_WITH_LEN("char(64)") },
     { C_STRING_WITH_LEN("utf8") }
+  },
+  {
+    { C_STRING_WITH_LEN("time_zone") },
+    { C_STRING_WITH_LEN("char(64)") },
+    { C_STRING_WITH_LEN("latin1") }
   }
 };
 
@@ -183,6 +188,14 @@
 
   if (et->expression)
   {
+    const String *tz_name= thd->variables.time_zone->get_name();
+    if (!is_update || !et->starts_null)
+    {
+      fields[ET_FIELD_TIME_ZONE]->set_notnull();
+      fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(),
+                                        tz_name->charset());
+    }
+
     fields[ET_FIELD_INTERVAL_EXPR]->set_notnull();
     fields[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, TRUE);
 
@@ -197,26 +210,40 @@
 
     if (!et->starts_null)
     {
+      TIME time;
+      my_tz_UTC->gmt_sec_to_TIME(&time, et->starts);
+
       fields[ET_FIELD_STARTS]->set_notnull();
-      fields[ET_FIELD_STARTS]->store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
+      fields[ET_FIELD_STARTS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
     }
 
     if (!et->ends_null)
     {
+      TIME time;
+      my_tz_UTC->gmt_sec_to_TIME(&time, et->ends);
+
       fields[ET_FIELD_ENDS]->set_notnull();
-      fields[ET_FIELD_ENDS]->store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
+      fields[ET_FIELD_ENDS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
     }
   }
-  else if (et->execute_at.year)
+  else if (et->execute_at)
   {
+    const String *tz_name= thd->variables.time_zone->get_name();
+    fields[ET_FIELD_TIME_ZONE]->set_notnull();
+    fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(),
+                                      tz_name->charset());
+
     fields[ET_FIELD_INTERVAL_EXPR]->set_null();
     fields[ET_FIELD_TRANSIENT_INTERVAL]->set_null();
     fields[ET_FIELD_STARTS]->set_null();
     fields[ET_FIELD_ENDS]->set_null();
     
+    TIME time;
+    my_tz_UTC->gmt_sec_to_TIME(&time, et->execute_at);
+
     fields[ET_FIELD_EXECUTE_AT]->set_notnull();
     fields[ET_FIELD_EXECUTE_AT]->
-                        store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME);
+                        store_time(&time, MYSQL_TIMESTAMP_DATETIME);
   }
   else
   {
@@ -527,6 +554,8 @@
 
   if (check_parse_params(thd, parse_data))
     goto err;
+  if (parse_data->do_not_create)
+    goto ok;
 
   DBUG_PRINT("info", ("open mysql.event for update"));
   if (open_event_table(thd, TL_WRITE, &table))
@@ -587,7 +616,7 @@
     goto err;
   }
 
-  if (!(parse_data->expression) && !(parse_data->execute_at.year))
+  if (!(parse_data->expression) && !(parse_data->execute_at))
   {
     DBUG_PRINT("error", ("neither expression nor execute_at are set!"));
     my_error(ER_EVENT_NEITHER_M_EXPR_NOR_M_AT, MYF(0));
@@ -664,7 +693,7 @@
     goto err;
   }
 
-  if (check_parse_params(thd, parse_data))
+  if (check_parse_params(thd, parse_data) || parse_data->do_not_create)
     goto err;
 
   DBUG_PRINT("info", ("dbname: %s", parse_data->dbname.str));
@@ -963,7 +992,7 @@
     my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
   else if ((ret= find_named_event(thd, dbname, name, table)))
     my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
-  else if ((ret= etn->load_from_row(table)))
+  else if ((ret= etn->load_from_row(thd, table)))
     my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
 
   if (table)

--- 1.26/sql/event_queue.cc	2007-03-07 08:06:18 +03:00
+++ 1.27/sql/event_queue.cc	2007-03-20 00:37:25 +03:00
@@ -65,8 +65,10 @@
 static int 
 event_queue_element_compare_q(void *vptr, byte* a, byte *b)
 {
-  return my_time_compare(&((Event_queue_element *)a)->execute_at,
-                         &((Event_queue_element *)b)->execute_at);
+  my_time_t lhs = ((Event_queue_element *)a)->execute_at;
+  my_time_t rhs = ((Event_queue_element *)b)->execute_at;
+
+  return (lhs < rhs ? -1 : (lhs > rhs ? 1 : 0));
 }
 
 
@@ -84,7 +86,7 @@
 {
   mutex_last_unlocked_in_func= mutex_last_locked_in_func=
     mutex_last_attempted_lock_in_func= "";
-  set_zero_time(&next_activation_at, MYSQL_TIMESTAMP_DATETIME);
+  next_activation_at= 0;
 }
 
 
@@ -497,15 +499,11 @@
     DBUG_PRINT("info", ("exec_at: %lu  starts: %lu  ends: %lu  execs_so_far: %u  "
                         "expr: %ld  et.exec_at: %ld  now: %ld  "
                         "(et.exec_at - now): %d  if: %d",
-                        (long) TIME_to_ulonglong_datetime(&et->execute_at),
-                        (long) TIME_to_ulonglong_datetime(&et->starts),
-                        (long) TIME_to_ulonglong_datetime(&et->ends),
-                        et->execution_count,
-                        (long) et->expression,
-                        (long) (sec_since_epoch_TIME(&et->execute_at)),
-                        (long) now,
-                        (int) (sec_since_epoch_TIME(&et->execute_at) - now),
-                        sec_since_epoch_TIME(&et->execute_at) <= now));
+                        (long) et->execute_at, (long) et->starts,
+                        (long) et->ends, et->execution_count,
+                        (long) et->expression, (long) et->execute_at,
+                        (long) now, (int) (et->execute_at - now),
+                        et->execute_at <= now));
   }
   DBUG_VOID_RETURN;
 #endif
@@ -534,7 +532,6 @@
                 Event_queue_element_for_exec **event_name)
 {
   bool ret= FALSE;
-  struct timespec top_time;
   *event_name= NULL;
   DBUG_ENTER("Event_queue::get_top_for_execution_if_time");
 
@@ -553,7 +550,7 @@
     if (!queue.elements)
     {
       /* There are no events in the queue */
-      set_zero_time(&next_activation_at, MYSQL_TIMESTAMP_DATETIME);
+      next_activation_at= 0;
 
       /* Wait on condition until signaled. Release LOCK_queue while waiting. */
       cond_wait(thd, NULL, queue_empty_msg, SCHED_FUNC, __LINE__);
@@ -565,16 +562,15 @@
 
     thd->end_time(); /* Get current time */
 
-    time_t seconds_to_next_event= 
-      sec_since_epoch_TIME(&top->execute_at) - thd->query_start();
     next_activation_at= top->execute_at;
-    if (seconds_to_next_event > 0)
+    if (next_activation_at > thd->query_start())
     {
       /*
         Not yet time for top event, wait on condition with
         time or until signaled. Release LOCK_queue while waiting.
       */
-      set_timespec(top_time, seconds_to_next_event);
+      struct timespec top_time;
+      set_timespec(top_time, next_activation_at - thd->query_start());
       cond_wait(thd, &top_time, queue_wait_msg, SCHED_FUNC, __LINE__);
 
       continue;
@@ -752,10 +748,11 @@
     printf("Last lock attempt at: %s:%u\n", mutex_last_attempted_lock_in_func,
                                             mutex_last_attempted_lock_at_line);
   printf("WOC             : %s\n", waiting_on_cond? "YES":"NO");
+
+  TIME time;
+  my_tz_UTC->gmt_sec_to_TIME(&time, next_activation_at);
   printf("Next activation : %04d-%02d-%02d %02d:%02d:%02d\n",
-         next_activation_at.year, next_activation_at.month,
-         next_activation_at.day, next_activation_at.hour,
-         next_activation_at.minute, next_activation_at.second);
+         time.year, time.month, time.day, time.hour, time.minute, time.second);
 
   DBUG_VOID_RETURN;
 }

--- 1.87/sql/event_data_objects.cc	2007-03-08 16:29:27 +03:00
+++ 1.88/sql/event_data_objects.cc	2007-03-20 00:42:03 +03:00
@@ -101,7 +101,7 @@
 */
 
 Event_parse_data::Event_parse_data()
-  :on_completion(ON_COMPLETION_DROP), status(ENABLED),
+  :on_completion(ON_COMPLETION_DROP), status(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)
@@ -109,9 +109,7 @@
   DBUG_ENTER("Event_parse_data::Event_parse_data");
 
   /* Actually in the parser STARTS is always set */
-  set_zero_time(&starts, MYSQL_TIMESTAMP_DATETIME);
-  set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME);
-  set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
+  starts= ends= execute_at= 0;
 
   body.str= comment.str= NULL;
   body.length= comment.length= 0;
@@ -224,6 +222,55 @@
 
 
 /*
+  This function is called on CREATE EVENT or ALTER EVENT.  When either
+  ENDS or AT is in the past, we are trying to create an event that
+  will never be executed.  If it has ON COMPLETION NOT PRESERVE
+  (default), then it would normally be dropped already, so on CREATE
+  EVENT we give a warning, and do not create anyting.  On ALTER EVENT
+  we give a error, and do not change the event.
+
+  If the event has ON COMPLETION PRESERVE, then we see if the event is
+  created or altered to the ENABLED (default) state.  If so, then we
+  give a warning, and change the state to DISABLED.
+
+  Otherwise it is a valid event in ON COMPLETION PRESERVE DISABLE
+  state.
+*/
+
+void
+Event_parse_data::check_if_in_the_past(THD *thd, my_time_t ltime_utc)
+{
+  if (ltime_utc >= (my_time_t) thd->query_start())
+    return;
+
+  if (on_completion == ON_COMPLETION_DROP)
+  {
+    switch (thd->lex->sql_command) {
+    case SQLCOM_CREATE_EVENT:
+      push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+                   ER_EVENT_CANNOT_CREATE_IN_THE_PAST,
+                   ER(ER_EVENT_CANNOT_CREATE_IN_THE_PAST));
+      break;
+    case SQLCOM_ALTER_EVENT:
+      my_error(ER_EVENT_CANNOT_ALTER_IN_THE_PAST, MYF(0));
+      break;
+    default:
+      DBUG_ASSERT(0);
+    }
+
+    do_not_create= TRUE;
+  }
+  else if (status == ENABLED)
+  {
+    status= DISABLED;
+    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+                 ER_EVENT_EXEC_TIME_IN_THE_PAST,
+                 ER(ER_EVENT_EXEC_TIME_IN_THE_PAST));
+  }
+}
+
+
+/*
   Sets time for execution for one-time event.
 
   SYNOPSIS
@@ -240,8 +287,7 @@
 {
   my_bool not_used;
   TIME ltime;
-  my_time_t t;
-  TIME time_tmp;
+  my_time_t ltime_utc;
 
   DBUG_ENTER("Event_parse_data::init_execute_at");
 
@@ -256,35 +302,20 @@
                       (starts_null && ends_null)));
   DBUG_ASSERT(starts_null && ends_null);
 
-  /* let's check whether time is in the past */
-  thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,
-                                            (my_time_t) thd->query_start());
-
   if ((not_used= item_execute_at->get_date(&ltime, TIME_NO_ZERO_DATE)))
     goto wrong_value;
 
-  if (TIME_to_ulonglong_datetime(&ltime) <
-      TIME_to_ulonglong_datetime(&time_tmp))
-  {
-    my_error(ER_EVENT_EXEC_TIME_IN_THE_PAST, MYF(0));
-    DBUG_RETURN(ER_WRONG_VALUE);
-  }
-
-  /*
-    This may result in a 1970-01-01 date if ltime is > 2037-xx-xx.
-    CONVERT_TZ has similar problem.
-    mysql_priv.h currently lists 
-      #define TIMESTAMP_MAX_YEAR 2038 (see TIME_to_timestamp())
-  */
-  my_tz_UTC->gmt_sec_to_TIME(&ltime,t=TIME_to_timestamp(thd,&ltime,&not_used));
-  if (!t)
+  ltime_utc= TIME_to_timestamp(thd,&ltime,&not_used);
+  if (!ltime_utc)
   {
     DBUG_PRINT("error", ("Execute AT after year 2037"));
     goto wrong_value;
   }
 
+  check_if_in_the_past(thd, ltime_utc);
+
   execute_at_null= FALSE;
-  execute_at= ltime;
+  execute_at= ltime_utc;
   DBUG_RETURN(0);
 
 wrong_value:
@@ -424,8 +455,8 @@
 Event_parse_data::init_starts(THD *thd)
 {
   my_bool not_used;
-  TIME ltime, time_tmp;
-  my_time_t t;
+  TIME ltime;
+  my_time_t ltime_utc;
 
   DBUG_ENTER("Event_parse_data::init_starts");
   if (!item_starts)
@@ -437,36 +468,15 @@
   if ((not_used= item_starts->get_date(&ltime, TIME_NO_ZERO_DATE)))
     goto wrong_value;
 
-  /*
-    Let's check whether time is in the past.
-    Note: This call is not post year 2038 safe. That's because
-          thd->query_start() is of time_t, while gmt_sec_to_TIME()
-          wants my_time_t. In the case time_t is larger than my_time_t
-          an overflow might happen and events subsystem will not work as
-          expected.
-  */
-  thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,
-                                            (my_time_t) thd->query_start());
-
-  DBUG_PRINT("info",("now: %ld  starts: %ld",
-                     (long) TIME_to_ulonglong_datetime(&time_tmp),
-                     (long) TIME_to_ulonglong_datetime(&ltime)));
-  if (TIME_to_ulonglong_datetime(&ltime) <
-      TIME_to_ulonglong_datetime(&time_tmp))
+  ltime_utc= TIME_to_timestamp(thd, &ltime, &not_used);
+  if (!ltime_utc)
     goto wrong_value;
 
-  /*
-    Again, after 2038 this code won't work. As
-    mysql_priv.h currently lists
-      #define TIMESTAMP_MAX_YEAR 2038 (see TIME_to_timestamp())
-  */
-  my_tz_UTC->gmt_sec_to_TIME(&ltime,t=TIME_to_timestamp(thd, &ltime,
-                                                        &not_used));
-  if (!t)
-    goto wrong_value;
+  DBUG_PRINT("info",("now: %ld  starts: %ld",
+                     (long) thd->query_start(), (long) ltime_utc));
 
-  starts= ltime;
   starts_null= FALSE;
+  starts= ltime_utc;
   DBUG_RETURN(0);
 
 wrong_value:
@@ -498,9 +508,9 @@
 int
 Event_parse_data::init_ends(THD *thd)
 {
-  TIME ltime, ltime_now;
   my_bool not_used;
-  my_time_t t;
+  TIME ltime;
+  my_time_t ltime_utc;
 
   DBUG_ENTER("Event_parse_data::init_ends");
   if (!item_ends)
@@ -513,34 +523,19 @@
   if ((not_used= item_ends->get_date(&ltime, TIME_NO_ZERO_DATE)))
     goto error_bad_params;
 
-  /*
-    Again, after 2038 this code won't work. As
-    mysql_priv.h currently lists
-      #define TIMESTAMP_MAX_YEAR 2038 (see TIME_to_timestamp())
-  */
-  DBUG_PRINT("info", ("get the UTC time"));
-  my_tz_UTC->gmt_sec_to_TIME(&ltime,t=TIME_to_timestamp(thd, &ltime,
-                                                        &not_used));
-  if (!t)
+  ltime_utc= TIME_to_timestamp(thd, &ltime, &not_used);
+  if (!ltime_utc)
     goto error_bad_params;
 
   /* Check whether ends is after starts */
   DBUG_PRINT("info", ("ENDS after STARTS?"));
-  if (!starts_null && my_time_compare(&starts, &ltime) != -1)
+  if (!starts_null && starts >= ltime_utc)
     goto error_bad_params;
 
-  /*
-    The parser forces starts to be provided but one day STARTS could be
-    set before NOW() and in this case the following check should be done.
-    Check whether ENDS is not in the past.
-  */
-  DBUG_PRINT("info", ("ENDS after NOW?"));
-  my_tz_UTC->gmt_sec_to_TIME(&ltime_now, (my_time_t)thd->query_start());
-  if (my_time_compare(&ltime_now, &ltime) == 1)
-    goto error_bad_params;
+  check_if_in_the_past(thd, ltime_utc);
 
-  ends= ltime;
   ends_null= FALSE;
+  ends= ltime_utc;
   DBUG_RETURN(0);
 
 error_bad_params:
@@ -656,6 +651,7 @@
   init_alloc_root(&mem_root, 256, 512);
   dbname.str= name.str= NULL;
   dbname.length= name.length= 0;
+  time_zone= NULL;
   DBUG_VOID_RETURN;
 }
 
@@ -716,6 +712,16 @@
 }
 
 
+bool
+Event_basic::load_time_zone(THD *thd, const LEX_STRING tz_name)
+{
+  String str(tz_name.str, &my_charset_latin1);
+  time_zone= my_tz_find(thd, &str);
+
+  return (time_zone == NULL);
+}
+
+
 /*
   Constructor
 
@@ -730,10 +736,7 @@
 {
   DBUG_ENTER("Event_queue_element::Event_queue_element");
 
-  set_zero_time(&starts, MYSQL_TIMESTAMP_DATETIME);
-  set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME);
-  set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
-  set_zero_time(&last_executed, MYSQL_TIMESTAMP_DATETIME);
+  starts= ends= execute_at= last_executed= 0;
   starts_null= ends_null= execute_at_null= TRUE;
 
   DBUG_VOID_RETURN;
@@ -833,7 +836,7 @@
   Loads an event's body from a row from mysql.event
 
   SYNOPSIS
-    Event_job_data::load_from_row(MEM_ROOT *mem_root, TABLE *table)
+    Event_job_data::load_from_row(THD *thd, TABLE *table)
 
   RETURN VALUE
     0                      OK
@@ -846,7 +849,7 @@
 */
 
 int
-Event_job_data::load_from_row(TABLE *table)
+Event_job_data::load_from_row(THD *thd, TABLE *table)
 {
   char *ptr;
   uint len;
@@ -858,9 +861,12 @@
   if (table->s->fields != ET_FIELD_COUNT)
     goto error;
 
+  LEX_STRING tz_name;
   load_string_fields(table->field, ET_FIELD_DB, &dbname, ET_FIELD_NAME, &name,
                      ET_FIELD_BODY, &body, ET_FIELD_DEFINER, &definer,
-                     ET_FIELD_COUNT);
+                     ET_FIELD_TIME_ZONE, &tz_name, ET_FIELD_COUNT);
+  if (load_time_zone(thd, tz_name))
+    goto error;
 
   ptr= strchr(definer.str, '@');
 
@@ -887,7 +893,7 @@
   Loads an event from a row from mysql.event
 
   SYNOPSIS
-    Event_queue_element::load_from_row(MEM_ROOT *mem_root, TABLE *table)
+    Event_queue_element::load_from_row(THD *thd, TABLE *table)
 
   RETURN VALUE
     0                      OK
@@ -900,10 +906,10 @@
 */
 
 int
-Event_queue_element::load_from_row(TABLE *table)
+Event_queue_element::load_from_row(THD *thd, TABLE *table)
 {
   char *ptr;
-  bool res1, res2;
+  TIME time;
 
   DBUG_ENTER("Event_queue_element::load_from_row");
 
@@ -913,29 +919,44 @@
   if (table->s->fields != ET_FIELD_COUNT)
     goto error;
 
+  LEX_STRING tz_name;
   load_string_fields(table->field, ET_FIELD_DB, &dbname, ET_FIELD_NAME, &name,
-                     ET_FIELD_DEFINER, &definer, ET_FIELD_COUNT);
+                     ET_FIELD_DEFINER, &definer,
+                     ET_FIELD_TIME_ZONE, &tz_name, ET_FIELD_COUNT);
+  if (load_time_zone(thd, tz_name))
+    goto error;
 
   starts_null= table->field[ET_FIELD_STARTS]->is_null();
-  res1= table->field[ET_FIELD_STARTS]->get_date(&starts, TIME_NO_ZERO_DATE);
+  if (!starts_null)
+  {
+    table->field[ET_FIELD_STARTS]->get_date(&time, TIME_NO_ZERO_DATE);
+    starts= sec_since_epoch_TIME(&time);
+  }
 
   ends_null= table->field[ET_FIELD_ENDS]->is_null();
-  res2= table->field[ET_FIELD_ENDS]->get_date(&ends, TIME_NO_ZERO_DATE);
+  if (!ends_null)
+  {
+    table->field[ET_FIELD_ENDS]->get_date(&time, TIME_NO_ZERO_DATE);
+    ends= sec_since_epoch_TIME(&time);
+  }
 
   if (!table->field[ET_FIELD_INTERVAL_EXPR]->is_null())
     expression= table->field[ET_FIELD_INTERVAL_EXPR]->val_int();
   else
     expression= 0;
   /*
-    If res1 and res2 are TRUE then both fields are empty.
+    If neigher STARTS and ENDS is set, then both fields are empty.
     Hence, if ET_FIELD_EXECUTE_AT is empty there is an error.
   */
   execute_at_null= table->field[ET_FIELD_EXECUTE_AT]->is_null();
   DBUG_ASSERT(!(starts_null && ends_null && !expression && execute_at_null));
-  if (!expression &&
-      table->field[ET_FIELD_EXECUTE_AT]->get_date(&execute_at,
-                                                  TIME_NO_ZERO_DATE))
-    goto error;
+  if (!expression && !execute_at_null)
+  {
+    if (table->field[ET_FIELD_EXECUTE_AT]->get_date(&time,
+                                                    TIME_NO_ZERO_DATE))
+      goto error;
+    execute_at= sec_since_epoch_TIME(&time);
+  }
 
   /*
     We load the interval type from disk as string and then map it to
@@ -962,11 +983,14 @@
     interval= (interval_type) i;
   }
 
-  table->field[ET_FIELD_LAST_EXECUTED]->get_date(&last_executed,
-                                                 TIME_NO_ZERO_DATE);
+  if (!table->field[ET_FIELD_LAST_EXECUTED]->is_null())
+  {
+    table->field[ET_FIELD_LAST_EXECUTED]->get_date(&time,
+                                                   TIME_NO_ZERO_DATE);
+    last_executed= sec_since_epoch_TIME(&time);
+  }
   last_executed_changed= FALSE;
 
-
   if ((ptr= get_field(&mem_root, table->field[ET_FIELD_STATUS])) == NullS)
     goto error;
 
@@ -992,7 +1016,7 @@
   Loads an event from a row from mysql.event
 
   SYNOPSIS
-    Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
+    Event_timed::load_from_row(THD *thd, TABLE *table)
 
   RETURN VALUE
     0                      OK
@@ -1005,14 +1029,14 @@
 */
 
 int
-Event_timed::load_from_row(TABLE *table)
+Event_timed::load_from_row(THD *thd, TABLE *table)
 {
   char *ptr;
   uint len;
 
   DBUG_ENTER("Event_timed::load_from_row");
 
-  if (Event_queue_element::load_from_row(table))
+  if (Event_queue_element::load_from_row(thd, table))
     goto error;
 
   load_string_fields(table->field, ET_FIELD_BODY, &body, ET_FIELD_COUNT);
@@ -1048,11 +1072,30 @@
 
 
 /*
-  Computes the sum of a timestamp plus interval. Presumed is that at least one
-  previous execution has occured.
+  add_interval() adds a specified interval to time 'ltime' in time
+  zone 'time_zone', and returns the result converted to the number of
+  seconds since epoch (aka Unix time; in UTC time zone).  Zero result
+  means an error.
+*/
+static
+my_time_t
+add_interval(TIME *ltime, const Time_zone *time_zone,
+             interval_type scale, INTERVAL interval)
+{
+  if (date_add_interval(ltime, scale, interval))
+    return 0;
+
+  my_bool not_used;
+  return time_zone->TIME_to_gmt_sec(ltime, &not_used);
+}
+
+
+/*
+  Computes the sum of a timestamp plus interval.
 
   SYNOPSIS
-    get_next_time(TIME *start, int interval_value, interval_type interval)
+    get_next_time()
+      time_zone     event time zone
       next          the sum
       start         add interval_value to this time
       time_now      current time
@@ -1069,26 +1112,19 @@
        seconds as resolution for computation.
     2) In all other cases - MONTH, QUARTER, YEAR we use MONTH as resolution
        and PERIOD_DIFF()'s implementation
-    3) We get the difference between time_now and `start`, then divide it
-       by the months, respectively seconds and round up. Then we multiply
-       monts/seconds by the rounded value and add it to `start` -> we get
-       the next execution time.
 */
 
 static
-bool get_next_time(TIME *next, TIME *start, TIME *time_now, TIME *last_exec,
+bool get_next_time(const Time_zone *time_zone, my_time_t *next,
+                   my_time_t start, my_time_t time_now,
                    int i_value, interval_type i_type)
 {
-  bool ret;
-  INTERVAL interval;
-  TIME tmp;
-  longlong months=0, seconds=0;
   DBUG_ENTER("get_next_time");
-  DBUG_PRINT("enter", ("start: %lu  now: %lu",
-                       (long) TIME_to_ulonglong_datetime(start),
-                       (long) TIME_to_ulonglong_datetime(time_now)));
+  DBUG_PRINT("enter", ("start: %lu  now: %lu", (long) start, (long) time_now));
 
-  bzero(&interval, sizeof(interval));
+  DBUG_ASSERT(start <= time_now);
+
+  longlong months=0, seconds=0;
 
   switch (i_type) {
   case INTERVAL_YEAR:
@@ -1135,84 +1171,151 @@
     DBUG_ASSERT(0);
   }
   DBUG_PRINT("info", ("seconds: %ld  months: %ld", (long) seconds, (long) months));
+
+  TIME local_start;
+  TIME local_now;
+
+  /* Convert times from UTC to local. */
+  {
+    time_zone->gmt_sec_to_TIME(&local_start, start);
+    time_zone->gmt_sec_to_TIME(&local_now, time_now);
+  }
+
+  INTERVAL interval;
+  bzero(&interval, sizeof(interval));
+  my_time_t next_time= 0;
+
   if (seconds)
   {
     longlong seconds_diff;
     long microsec_diff;
+    bool negative= calc_time_diff(&local_now, &local_start, 1,
+                                  &seconds_diff, &microsec_diff);
+    if (!negative)
+    {
+      /*
+        The formula below returns the interval that, when added to
+        local_start, will always give the time in the future.
+      */
+      interval.second= seconds_diff - seconds_diff % seconds + seconds;
+      next_time= add_interval(&local_start, time_zone,
+                              INTERVAL_SECOND, interval);
+      if (next_time == 0)
+        goto done;
+    }
 
-    if (calc_time_diff(time_now, start, 1, &seconds_diff, &microsec_diff))
+    if (next_time <= time_now)
     {
-      DBUG_PRINT("error", ("negative difference"));
-      DBUG_ASSERT(0);
+      /*
+        If 'negative' is true above, then 'next_time == 0', and
+        'next_time <= time_now' is also true.  If negative is false,
+        then next_time was set, but perhaps to the value that is less
+        then time_now.  See below for elaboration.
+      */
+      DBUG_ASSERT(negative || next_time > 0);
+
+      /*
+        If local_now < local_start, i.e. STARTS time is in the future
+        according to the local time (it always in the past according
+        to UTC---this is a prerequisite of this function), then
+        STARTS is almost always in the past according to the local
+        time too.  However, in the time zone that has backward
+        Daylight Saving Time shift, the following may happen: suppose
+        we have a backward DST shift at certain date after 2:59:59,
+        i.e. local time goes 1:59:59, 2:00:00, ... , 2:59:59, (shift
+        here) 2:00:00 (again), ... , 2:59:59 (again), 3:00:00, ... .
+        Now suppose the time has passed the first 2:59:59, has been
+        shifted backward, and now is (the second) 2:20:00.  The user
+        does CREATE EVENT with STARTS 'current-date 2:40:00'.  Local
+        time 2:40:00 from create statement is treated by time
+        functions as the first such time, so according to UTC it comes
+        before the second 2:20:00.  But according to local time it is
+        obviously in the future, so we end up in this branch.
+
+        Since we are in the second pass through 2:00:00--2:59:59, and
+        any local time form this interval is treated by system
+        functions as the time from the first pass, we have to find the
+        time for the next execution that is past the DST-affected
+        interval (past the second 2:59:59 for our example,
+        i.e. starting from 3:00:00).  We do this in the loop until the
+        local time is mapped onto future UTC time.  'start' time is in
+        the past, so we may use 'do { } while' here, and add the first
+        interval right away.
+
+        Alternatively, it could be that local_now >= local_start.  Now
+        for the example above imagine we do CREATE EVENT with STARTS
+        'current-date 2:10:00'.  Local start 2:10 is in the past (now
+        is local 2:20), so we add an interval, and get next execution
+        time, say, 2:40.  It is in the future according to local time,
+        but, again, since we are in the second pass through
+        2:00:00--2:59:59, 2:40 will be converted into UTC time in the
+        past.  So we will end up in this branch again, and may add
+        intervals in a 'do { } while' loop.
+
+        Note that for any given event we may end up here only if event
+        next execution time will map to the time interval that is
+        passed twice, and only if the server was started during the
+        second pass, or the event is being created during the second
+        pass.  After that, we never will get here (unless we again
+        start the server during the second pass).  In other words,
+        such a condition is extremely rare.
+      */
+      interval.second= seconds;
+      do
+      {
+        next_time= add_interval(&local_start, time_zone,
+                                INTERVAL_SECOND, interval);
+        if (next_time == 0)
+          goto done;
+      }
+      while (next_time <= time_now);
     }
-    uint multiplier= (uint) (seconds_diff / seconds);
-    /*
-      Increase the multiplier is the modulus is not zero to make round up.
-      Or if time_now==start then we should not execute the same 
-      event two times for the same time
-      get the next exec if the modulus is not
-    */
-    DBUG_PRINT("info", ("multiplier: %d", multiplier));
-    if (seconds_diff % seconds || (!seconds_diff && last_exec->year) ||
-        TIME_to_ulonglong_datetime(time_now) ==
-          TIME_to_ulonglong_datetime(last_exec))
-      ++multiplier;
-    interval.second= seconds * multiplier;
-    DBUG_PRINT("info", ("multiplier: %lu  interval.second: %lu", (ulong) multiplier,
-                        (ulong) interval.second));
-    tmp= *start;
-    if (!(ret= date_add_interval(&tmp, INTERVAL_SECOND, interval)))
-      *next= tmp;
   }
   else
   {
-    /* PRESUMED is that at least one execution took already place */
-    int diff_months= (time_now->year - start->year)*12 +
-                     (time_now->month - start->month);
-    /*
-      Note: If diff_months is 0 that means we are in the same month as the
-      last execution which is also the first execution.
-    */
+    long diff_months= (long) (local_now.year - local_start.year)*12 +
+                      (local_now.month - local_start.month);
     /*
-      First we try with the smaller if not then + 1, because if we try with
-      directly with +1 we will be after the current date but it could be that
-      we will be 1 month ahead, so 2 steps are necessary.
+      Unlike for seconds above, the formula below returns the interval
+      that, when added to the local_start, will give the time in the
+      past, or somewhere in the current month.  We are interested in
+      the latter case, to see if this time has already passed, or is
+      yet to come this month.
+
+      Note that the time is guaranteed to be in the past unless
+      (diff_months % months == 0), but no good optimization is
+      possible here, because (diff_months % months == 0) is what will
+      happen most of the time, as get_next_time() will be called right
+      after the execution of the event.  We could pass last_executed
+      time to this function, and see if the execution has already
+      happened this month, but for that we will have to convert
+      last_executed from seconds since epoch to local broken-down
+      time, and this will greatly reduce the effect of the
+      optimization.  So instead we keep the code simple and clean.
     */
-    interval.month= (ulong) ((diff_months / months)*months);
-    /*
-      Check if the same month as last_exec (always set - prerequisite)
-      An event happens at most once per month so there is no way to
-      schedule it two times for the current month. This saves us from two
-      calls to date_add_interval() if the event was just executed.  But if
-      the scheduler is started and there was at least 1 scheduled date
-      skipped this one does not help and two calls to date_add_interval()
-      will be done, which is a bit more expensive but compared to the
-      rareness of the case is neglectable.
-    */
-    if (time_now->year == last_exec->year &&
-        time_now->month == last_exec->month)
-      interval.month+= (ulong) months;
-
-    tmp= *start;
-    if ((ret= date_add_interval(&tmp, INTERVAL_MONTH, interval)))
+    interval.month= (ulong) (diff_months - diff_months % months);
+    next_time= add_interval(&local_start, time_zone,
+                            INTERVAL_MONTH, interval);
+    if (next_time == 0)
       goto done;
 
-    /* If `tmp` is still before time_now just add one more time the interval */
-    if (my_time_compare(&tmp, time_now) == -1)
-    { 
-      interval.month+= (ulong) months;
-      tmp= *start;
-      if ((ret= date_add_interval(&tmp, INTERVAL_MONTH, interval)))
+    if (next_time <= time_now)
+    {
+      interval.month= (ulong) months;
+      next_time= add_interval(&local_start, time_zone,
+                              INTERVAL_MONTH, interval);
+      if (next_time == 0)
         goto done;
     }
-    *next= tmp;
-    /* assert on that the next is after now */
-    DBUG_ASSERT(1==my_time_compare(next, time_now));
   }
 
+  DBUG_ASSERT(time_now < next_time);
+
+  *next= next_time;
+
 done:
-  DBUG_PRINT("info", ("next: %lu", (long) TIME_to_ulonglong_datetime(next)));
-  DBUG_RETURN(ret);
+  DBUG_PRINT("info", ("next_time: %ld", (long) next_time));
+  DBUG_RETURN(next_time == 0);
 }
 
 
@@ -1227,20 +1330,17 @@
     TRUE   Error
 
   NOTES
-    The time is set in execute_at, if no more executions the latter is set to
-    0000-00-00.
+    The time is set in execute_at, if no more executions the latter is
+    set to 0.
 */
 
 bool
 Event_queue_element::compute_next_execution_time()
 {
-  TIME time_now;
-  int tmp;
+  my_time_t time_now;
   DBUG_ENTER("Event_queue_element::compute_next_execution_time");
   DBUG_PRINT("enter", ("starts: %lu  ends: %lu  last_executed: %lu  this: 0x%lx",
-                       (long) TIME_to_ulonglong_datetime(&starts),
-                       (long) TIME_to_ulonglong_datetime(&ends),
-                       (long) TIME_to_ulonglong_datetime(&last_executed),
+                       (long) starts, (long) ends, (long) last_executed,
                        (long) this));
 
   if (status == Event_queue_element::DISABLED)
@@ -1253,7 +1353,7 @@
   if (!expression)
   {
     /* Let's check whether it was executed */
-    if (last_executed.year)
+    if (last_executed)
     {
       DBUG_PRINT("info",("One-time event %s.%s of was already executed",
                          dbname.str, name.str));
@@ -1266,17 +1366,16 @@
     goto ret;
   }
 
-  my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t)current_thd->query_start());
+  time_now= current_thd->query_start();
 
-  DBUG_PRINT("info",("NOW: [%lu]",
-                     (ulong) TIME_to_ulonglong_datetime(&time_now)));
+  DBUG_PRINT("info",("NOW: [%lu]", (ulong) time_now));
 
   /* if time_now is after ends don't execute anymore */
-  if (!ends_null && (tmp= my_time_compare(&ends, &time_now)) == -1)
+  if (!ends_null && ends < time_now)
   {
     DBUG_PRINT("info", ("NOW after ENDS, don't execute anymore"));
     /* time_now is after ends. don't execute anymore */
-    set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
+    execute_at= 0;
     execute_at_null= TRUE;
     if (on_completion == Event_queue_element::ON_COMPLETION_DROP)
       dropped= TRUE;
@@ -1293,12 +1392,11 @@
     Let's check whether time_now is before starts.
     If so schedule for starts.
   */
-  if (!starts_null && (tmp= my_time_compare(&time_now, &starts)) < 1)
+  if (!starts_null && time_now <= starts)
   {
-    if (tmp == 0 && my_time_compare(&starts, &last_executed) == 0)
+    if (time_now == starts && starts == last_executed)
     {
       /*
-        time_now = starts = last_executed
         do nothing or we will schedule for second time execution at starts.
       */
     }
@@ -1324,26 +1422,25 @@
       If not set then schedule for now.
     */
     DBUG_PRINT("info", ("Both STARTS & ENDS are set"));
-    if (!last_executed.year)
+    if (!last_executed)
     {
       DBUG_PRINT("info", ("Not executed so far."));
     }
 
     {
-      TIME next_exec;
+      my_time_t next_exec;
 
-      if (get_next_time(&next_exec, &starts, &time_now,
-                        last_executed.year? &last_executed:&starts,
+      if (get_next_time(time_zone, &next_exec, starts, time_now,
                         (int) expression, interval))
         goto err;
 
       /* There was previous execution */
-      if (my_time_compare(&ends, &next_exec) == -1)
+      if (ends < next_exec)
       {
         DBUG_PRINT("info", ("Next execution of %s after ENDS. Stop executing.",
                    name.str));
         /* Next execution after ends. No more executions */
-        set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
+        execute_at= 0;
         execute_at_null= TRUE;
         if (on_completion == Event_queue_element::ON_COMPLETION_DROP)
           dropped= TRUE;
@@ -1352,8 +1449,7 @@
       }
       else
       {
-        DBUG_PRINT("info",("Next[%lu]",
-                           (ulong) TIME_to_ulonglong_datetime(&next_exec)));
+        DBUG_PRINT("info",("Next[%lu]", (ulong) next_exec));
         execute_at= next_exec;
         execute_at_null= FALSE;
       }
@@ -1368,15 +1464,14 @@
       Both starts and m_ends are not set, so we schedule for the next
       based on last_executed.
     */
-    if (last_executed.year)
+    if (last_executed)
     {
-      TIME next_exec;
-      if (get_next_time(&next_exec, &starts, &time_now, &last_executed,
+      my_time_t next_exec;
+      if (get_next_time(time_zone, &next_exec, starts, time_now,
                         (int) expression, interval))
         goto err;
       execute_at= next_exec;
-      DBUG_PRINT("info",("Next[%lu]",
-                         (ulong) TIME_to_ulonglong_datetime(&next_exec)));
+      DBUG_PRINT("info",("Next[%lu]", (ulong) next_exec));
     }
     else
     {
@@ -1398,20 +1493,18 @@
         Hence schedule for starts + m_expression in case last_executed
         is not set, otherwise to last_executed + m_expression
       */
-      if (!last_executed.year)
+      if (!last_executed)
       {
         DBUG_PRINT("info", ("Not executed so far."));
       }
 
       {
-        TIME next_exec;
-        if (get_next_time(&next_exec, &starts, &time_now,
-                          last_executed.year? &last_executed:&starts,
+        my_time_t next_exec;
+        if (get_next_time(time_zone, &next_exec, starts, time_now,
                           (int) expression, interval))
           goto err;
         execute_at= next_exec;
-        DBUG_PRINT("info",("Next[%lu]",
-                           (ulong) TIME_to_ulonglong_datetime(&next_exec)));
+        DBUG_PRINT("info",("Next[%lu]", (ulong) next_exec));
       }
       execute_at_null= FALSE;
     }
@@ -1426,20 +1519,20 @@
         If last_executed is not set then schedule for now
       */
 
-      if (!last_executed.year)
+      if (!last_executed)
         execute_at= time_now;
       else
       {
-        TIME next_exec;
+        my_time_t next_exec;
 
-        if (get_next_time(&next_exec, &starts, &time_now, &last_executed,
+        if (get_next_time(time_zone, &next_exec, starts, time_now,
                           (int) expression, interval))
           goto err;
 
-        if (my_time_compare(&ends, &next_exec) == -1)
+        if (ends < next_exec)
         {
           DBUG_PRINT("info", ("Next execution after ENDS. Stop executing."));
-          set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
+          execute_at= 0;
           execute_at_null= TRUE;
           status= Event_queue_element::DISABLED;
           status_changed= TRUE;
@@ -1448,8 +1541,7 @@
         }
         else
         {
-          DBUG_PRINT("info", ("Next[%lu]",
-                              (ulong) TIME_to_ulonglong_datetime(&next_exec)));
+          DBUG_PRINT("info", ("Next[%lu]", (ulong) next_exec));
           execute_at= next_exec;
           execute_at_null= FALSE;
         }
@@ -1458,8 +1550,7 @@
     goto ret;
   }
 ret:
-  DBUG_PRINT("info", ("ret: 0 execute_at: %lu",
-                      (long) TIME_to_ulonglong_datetime(&execute_at)));
+  DBUG_PRINT("info", ("ret: 0 execute_at: %lu", (long) execute_at));
   DBUG_RETURN(FALSE);
 err:
   DBUG_PRINT("info", ("ret=1"));
@@ -1479,12 +1570,9 @@
 void
 Event_queue_element::mark_last_executed(THD *thd)
 {
-  TIME time_now;
-
   thd->end_time();
-  my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t) thd->query_start());
 
-  last_executed= time_now; /* was execute_at */
+  last_executed= thd->query_start();
   last_executed_changed= TRUE;
   
   execution_count++;
@@ -1538,8 +1626,11 @@
 
   if (last_executed_changed)
   {
+    TIME time;
+    my_tz_UTC->gmt_sec_to_TIME(&time, last_executed);
+
     fields[ET_FIELD_LAST_EXECUTED]->set_notnull();
-    fields[ET_FIELD_LAST_EXECUTED]->store_time(&last_executed,
+    fields[ET_FIELD_LAST_EXECUTED]->store_time(&time,
                                                MYSQL_TIMESTAMP_DATETIME);
     last_executed_changed= FALSE;
   }
@@ -1561,6 +1652,26 @@
 }
 
 
+static
+void
+append_datetime(String *buf, Time_zone *time_zone, my_time_t secs,
+                const char *name, uint len)
+{
+  char dtime_buff[20*2+32];/* +32 to make my_snprintf_{8bit|ucs2} happy */
+  buf->append(STRING_WITH_LEN(" "));
+  buf->append(name, len);
+  buf->append(STRING_WITH_LEN(" '"));
+  /*
+    Pass the buffer and the second param tells fills the buffer and
+    returns the number of chars to copy.
+  */
+  TIME time;
+  time_zone->gmt_sec_to_TIME(&time, secs);
+  buf->append(dtime_buff, my_datetime_to_str(&time, dtime_buff));
+  buf->append(STRING_WITH_LEN("'"));
+}
+
+
 /*
   Get SHOW CREATE EVENT as string
 
@@ -1600,17 +1711,17 @@
     buf->append(' ');
     LEX_STRING *ival= &interval_type_to_name[interval];
     buf->append(ival->str, ival->length);
+
+    if (!starts_null)
+      append_datetime(buf, time_zone, starts, STRING_WITH_LEN("STARTS"));
+
+    if (!ends_null)
+      append_datetime(buf, time_zone, ends, STRING_WITH_LEN("ENDS"));
   }
   else
   {
-    char dtime_buff[20*2+32];/* +32 to make my_snprintf_{8bit|ucs2} happy */
-    buf->append(STRING_WITH_LEN(" ON SCHEDULE AT '"));
-    /*
-      Pass the buffer and the second param tells fills the buffer and
-      returns the number of chars to copy.
-    */
-    buf->append(dtime_buff, my_datetime_to_str(&execute_at, dtime_buff));
-    buf->append(STRING_WITH_LEN("'"));
+    append_datetime(buf, time_zone, execute_at,
+                    STRING_WITH_LEN("ON SCHEDULE AT"));
   }
 
   if (on_completion == Event_timed::ON_COMPLETION_DROP)
@@ -1654,6 +1765,7 @@
 Event_job_data::get_fake_create_event(THD *thd, String *buf)
 {
   DBUG_ENTER("Event_job_data::get_create_event");
+  /* FIXME: "EVERY 3337 HOUR" is asking for trouble. */
   buf->append(STRING_WITH_LEN("CREATE EVENT anonymous ON SCHEDULE "
                               "EVERY 3337 HOUR DO "));
   buf->append(body.str, body.length);
@@ -1704,6 +1816,9 @@
     if (thd->enable_slow_log)
       sphead->m_flags|= sp_head::LOG_SLOW_STATEMENTS;
     sphead->m_flags|= sp_head::LOG_GENERAL_LOG;
+
+    /* Execute the event in its time zone. */
+    thd->variables.time_zone= time_zone;
 
     ret= sphead->execute_procedure(thd, &empty_item_list);
   }

--- 1.148/sql/share/errmsg.txt	2007-02-23 20:10:34 +03:00
+++ 1.149/sql/share/errmsg.txt	2007-03-20 00:37:37 +03:00
@@ -5518,8 +5518,7 @@
         eng "For float(M,D), double(M,D) or decimal(M,D), M must be >= D (column '%-.64s')."
 ER_WRONG_LOCK_OF_SYSTEM_TABLE
-        eng "You can't combine write-locking of system '%-.64s.%-.64s' table with other tables"
+        eng "You can't combine write-locking of system tables with other tables or lock types"
 ER_CONNECT_TO_FOREIGN_DATA_SOURCE
         eng "Unable to connect to foreign data source: %.64s"
         ger "Kann nicht mit Fremddatenquelle verbinden: %.64s"
@@ -5874,8 +5873,7 @@
         eng "ENDS is either invalid or before STARTS"
 ER_EVENT_EXEC_TIME_IN_THE_PAST
-        eng "Activation (AT) time is in the past"
-        ger "Aktivierungszeit (AT) liegt in der Vergangenheit"
+        eng "Event execution time is in the past. Event has been disabled"
 ER_EVENT_OPEN_TABLE_FAILED
         eng "Failed to open mysql.event"
@@ -6053,3 +6051,7 @@
 ER_BINLOG_PURGE_EMFILE
         eng "Too many files opened, please execute the command again"
+ER_EVENT_CANNOT_CREATE_IN_THE_PAST
+        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"

--- 1.215/mysql-test/r/view.result	2007-03-09 12:39:59 +03:00
+++ 1.216/mysql-test/r/view.result	2007-03-20 00:37:25 +03:00
@@ -900,6 +900,7 @@
 drop table t1;
 create table t1 (col1 int);
 create table t2 (col1 int);
+create table t3 (col1 datetime not null);
 create view v1 as select * from t1;
 create view v2 as select * from v1;
 create view v3 as select v2.col1 from v2,t2 where v2.col1 = t2.col1;
@@ -1004,8 +1005,8 @@
 insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from v2));
 ERROR HY000: The definition of table 'v2' prevents operation INSERT on table 'v3'.
 insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2));
-insert into mysql.time_zone values ('', (select CONVERT_TZ('20050101000000','UTC','MET') from t2));
-ERROR 23000: Column 'Use_leap_seconds' cannot be null
+insert into t3 values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2));
+ERROR 23000: Column 'col1' cannot be null
 create algorithm=temptable view v4 as select * from t1;
 insert into t1 values (1),(2),(3);
 insert into t1 (col1) values ((select max(col1) from v4));
@@ -1017,7 +1018,7 @@
 3
 3
 drop view v4,v3,v2,v1;
-drop table t1,t2;
+drop table t1,t2,t3;
 create table t1 (s1 int);
 create view v1 as select * from t1;
 handler v1 open as xx;
@@ -3320,3 +3321,38 @@
 DROP VIEW  `v-2`;
 DROP DATABASE `d-1`;
 USE test;
+DROP VIEW IF EXISTS v1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (i INT);
+CREATE VIEW v1 AS SELECT * FROM t1;
+ALTER VIEW v1 AS SELECT * FROM t1;
+SHOW CREATE VIEW v1;
+View	Create View
+v1	CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1`
+ALTER DEFINER=no_such@user_1 VIEW v1 AS SELECT * FROM t1;
+Warnings:
+Note	1449	There is no 'no_such'@'user_1' registered
+SHOW CREATE VIEW v1;
+View	Create View
+v1	CREATE ALGORITHM=UNDEFINED DEFINER=`no_such`@`user_1` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1`
+Warnings:
+Note	1449	There is no 'no_such'@'user_1' registered
+ALTER ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1;
+Warnings:
+Note	1449	There is no 'no_such'@'user_1' registered
+SHOW CREATE VIEW v1;
+View	Create View
+v1	CREATE ALGORITHM=MERGE DEFINER=`no_such`@`user_1` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1`
+Warnings:
+Note	1449	There is no 'no_such'@'user_1' registered
+ALTER ALGORITHM=TEMPTABLE DEFINER=no_such@user_2 VIEW v1 AS SELECT * FROM t1;
+Warnings:
+Note	1449	There is no 'no_such'@'user_2' registered
+SHOW CREATE VIEW v1;
+View	Create View
+v1	CREATE ALGORITHM=TEMPTABLE DEFINER=`no_such`@`user_2` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`i` AS `i` from `t1`
+Warnings:
+Note	1449	There is no 'no_such'@'user_2' registered
+DROP VIEW v1;
+DROP TABLE t1;
+End of 5.1 tests.

--- 1.10/mysql-test/r/skip_grants.result	2007-03-16 11:15:49 +03:00
+++ 1.11/mysql-test/r/skip_grants.result	2007-03-20 00:42:03 +03:00
@@ -58,6 +58,8 @@
 DROP FUNCTION f1;
 DROP FUNCTION f2;
 DROP FUNCTION f3;
+set global event_scheduler=1;
+ERROR HY000: The MySQL server is running with the --event-scheduler=DISABLED or --skip-grant-tables option so it cannot execute this statement
 select count(*) from information_schema.COLUMN_PRIVILEGES;
 count(*)
 0

--- 1.191/mysql-test/t/view.test	2007-03-09 12:40:25 +03:00
+++ 1.192/mysql-test/t/view.test	2007-03-20 00:37:25 +03:00
@@ -832,6 +832,7 @@
 #
 create table t1 (col1 int);
 create table t2 (col1 int);
+create table t3 (col1 datetime not null);
 create view v1 as select * from t1;
 create view v2 as select * from v1;
 create view v3 as select v2.col1 from v2,t2 where v2.col1 = t2.col1;
@@ -938,7 +939,7 @@
 insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from v2));
 insert into v3 (col1) values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2));
 -- error 1048
-insert into mysql.time_zone values ('', (select CONVERT_TZ('20050101000000','UTC','MET') from t2));
+insert into t3 values ((select CONVERT_TZ('20050101000000','UTC','MET') from t2));
 # temporary table algorithm view should be equal to subquery in the from clause
 create algorithm=temptable view v4 as select * from t1;
 insert into t1 values (1),(2),(3);
@@ -946,7 +947,7 @@
 select * from t1;
 
 drop view v4,v3,v2,v1;
-drop table t1,t2;
+drop table t1,t2,t3;
 
 #
 # HANDLER with VIEW
@@ -3214,3 +3215,30 @@
 DROP VIEW  `v-2`;
 DROP DATABASE `d-1`;
 USE test;
+
+
+#
+# Test that ALTER VIEW accepts DEFINER and ALGORITHM, see bug#16425.
+#
+--disable_warnings
+DROP VIEW IF EXISTS v1;
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (i INT);
+CREATE VIEW v1 AS SELECT * FROM t1;
+
+ALTER VIEW v1 AS SELECT * FROM t1;
+SHOW CREATE VIEW v1;
+ALTER DEFINER=no_such@user_1 VIEW v1 AS SELECT * FROM t1;
+SHOW CREATE VIEW v1;
+ALTER ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1;
+SHOW CREATE VIEW v1;
+ALTER ALGORITHM=TEMPTABLE DEFINER=no_such@user_2 VIEW v1 AS SELECT * FROM t1;
+SHOW CREATE VIEW v1;
+
+DROP VIEW v1;
+DROP TABLE t1;
+
+
+--echo End of 5.1 tests.

--- 1.12/mysql-test/t/skip_grants.test	2007-03-16 16:56:59 +03:00
+++ 1.13/mysql-test/t/skip_grants.test	2007-03-20 00:42:03 +03:00
@@ -115,3 +115,10 @@
 --error ER_OPTION_PREVENTS_STATEMENT
 set global event_scheduler=1;
 
+#
+# Bug#26285 Selecting information_schema crahes server
+#
+select count(*) from information_schema.COLUMN_PRIVILEGES;
+select count(*) from information_schema.SCHEMA_PRIVILEGES;
+select count(*) from information_schema.TABLE_PRIVILEGES;
+select count(*) from information_schema.USER_PRIVILEGES;

--- 1.150/sql/item_subselect.cc	2007-03-15 00:30:45 +03:00
+++ 1.151/sql/item_subselect.cc	2007-03-20 00:37:30 +03:00
@@ -2046,7 +2046,8 @@
     table->file->ha_index_init(tab->ref.key, 0);
   error= table->file->index_read(table->record[0],
                                  tab->ref.key_buff,
-                                 tab->ref.key_length,HA_READ_KEY_EXACT);
+                                 make_prev_keypart_map(tab->ref.key_parts),
+                                 HA_READ_KEY_EXACT);
   if (error &&
       error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
     error= report_error(table, error);
@@ -2155,7 +2156,8 @@
     table->file->ha_index_init(tab->ref.key, 1);
   error= table->file->index_read(table->record[0],
                                  tab->ref.key_buff,
-                                 tab->ref.key_length,HA_READ_KEY_EXACT);
+                                 make_prev_keypart_map(tab->ref.key_parts),
+                                 HA_READ_KEY_EXACT);
   if (error &&
       error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
     error= report_error(table, error);

--- 1.51/sql/tztime.cc	2007-03-17 02:13:19 +03:00
+++ 1.52/sql/tztime.cc	2007-03-20 00:37:37 +03:00
@@ -1505,26 +1505,20 @@
 
 
 /*
-  Prepare table list with time zone related tables from preallocated array
-  and add to global table list.
+  Prepare table list with time zone related tables from preallocated array.
 
   SYNOPSIS
     tz_init_table_list()
       tz_tabs         - pointer to preallocated array of MY_TZ_TABLES_COUNT
                         TABLE_LIST objects
-      global_next_ptr - pointer to variable which points to global_next member
-                        of last element of global table list (or list root
-                        then list is empty) (in/out).
 
   DESCRIPTION
     This function prepares list of TABLE_LIST objects which can be used
-    for opening of time zone tables from preallocated array. It also links
-    this list to the end of global table list (it will read and update
-    accordingly variable pointed by global_next_ptr for this).
+    for opening of time zone tables from preallocated array.
 */
 
 static void
-tz_init_table_list(TABLE_LIST *tz_tabs, TABLE_LIST ***global_next_ptr)
+tz_init_table_list(TABLE_LIST *tz_tabs)
 {
   bzero(tz_tabs, sizeof(TABLE_LIST) * MY_TZ_TABLES_COUNT);
 
@@ -1541,64 +1535,6 @@
     if (i != 0)
       tz_tabs[i].prev_global= &tz_tabs[i-1].next_global;
   }
-
-  /* Link into global list */
-  tz_tabs[0].prev_global= *global_next_ptr;
-  **global_next_ptr= tz_tabs;
-  /* Update last-global-pointer to point to pointer in last table */
-  *global_next_ptr= &tz_tabs[MY_TZ_TABLES_COUNT-1].next_global;
-}
-
-
-/*
-  Fake table list object, pointer to which is returned by
-  my_tz_get_tables_list() as indication of error.
-*/
-TABLE_LIST fake_time_zone_tables_list;
-
-/*
-  Create table list with time zone related tables and add it to the end
-  of global table list.
-
-  SYNOPSIS
-    my_tz_get_table_list()
-      thd             - current thread object
-      global_next_ptr - pointer to variable which points to global_next member
-                        of last element of global table list (or list root
-                        then list is empty) (in/out).
-
-  DESCRIPTION
-    This function creates list of TABLE_LIST objects allocated in thd's
-    memroot, which can be used for opening of time zone tables. It will also
-    link this list to the end of global table list (it will read and update
-    accordingly variable pointed by global_next_ptr for this).
-
-  NOTE
-    my_tz_check_n_skip_implicit_tables() function depends on fact that
-    elements of list created are allocated as TABLE_LIST[MY_TZ_TABLES_COUNT]
-    array.
-
-  RETURN VALUES
-    Returns pointer to first TABLE_LIST object, (could be 0 if time zone
-    tables don't exist) and &fake_time_zone_tables_list in case of error.
-*/
-
-TABLE_LIST *
-my_tz_get_table_list(THD *thd, TABLE_LIST ***global_next_ptr)
-{
-  TABLE_LIST *tz_tabs;
-  DBUG_ENTER("my_tz_get_table_list");
-
-  if (!time_zone_tables_exist)
-    DBUG_RETURN(0);
-
-  if (!(tz_tabs= (TABLE_LIST *)thd->alloc(sizeof(TABLE_LIST) *
-                                          MY_TZ_TABLES_COUNT)))
-    DBUG_RETURN(&fake_time_zone_tables_list);
-
-  tz_init_table_list(tz_tabs, global_next_ptr);
-
-  DBUG_RETURN(tz_tabs);
 }
 
 
@@ -1631,8 +1567,8 @@
 my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap)
 {
   THD *thd;
-  TABLE_LIST *tables= 0;
-  TABLE_LIST tables_buff[1+MY_TZ_TABLES_COUNT], **last_global_next_ptr;
+  TABLE_LIST tz_tables[1+MY_TZ_TABLES_COUNT];
+  Open_tables_state open_tables_state_backup;
   TABLE *table;
   Tz_names_entry *tmp_tzname;
   my_bool return_val= 1;
@@ -1694,19 +1630,23 @@
   */
 
   thd->set_db(db, sizeof(db)-1);
-  bzero((char*) &tables_buff, sizeof(TABLE_LIST));
-  tables_buff[0].alias= tables_buff[0].table_name=
+  bzero((char*) &tz_tables[0], sizeof(TABLE_LIST));
+  tz_tables[0].alias= tz_tables[0].table_name=
     (char*)"time_zone_leap_second";
-  tables_buff[0].lock_type= TL_READ;
-  tables_buff[0].db= db;
+  tz_tables[0].table_name_length= 21;
+  tz_tables[0].db= db;
+  tz_tables[0].db_length= sizeof(db)-1;
+  tz_tables[0].lock_type= TL_READ;
+
+  tz_init_table_list(tz_tables+1);
+  tz_tables[0].next_global= tz_tables[0].next_local= &tz_tables[1];
+  tz_tables[1].prev_global= &tz_tables[0].next_global;
+
   /*
-    Fill TABLE_LIST for the rest of the time zone describing tables
-    and link it to first one.
+    We need to open only mysql.time_zone_leap_second, but we try to
+    open all time zone tables to see if they exist.
   */
-  last_global_next_ptr= &(tables_buff[0].next_global);
-  tz_init_table_list(tables_buff + 1, &last_global_next_ptr);
-
-  if (simple_open_n_lock_tables(thd, tables_buff))
+  if (open_system_tables_for_read(thd, tz_tables, &open_tables_state_backup))
   {
     sql_print_warning("Can't open and lock time zone table: %s "
                       "trying to live without them", thd->net.last_error);
@@ -1714,7 +1654,6 @@
     return_val= time_zone_tables_exist= 0;
     goto end_with_setting_default_tz;
   }
-  tables= tables_buff + 1;
 
   /*
     Now we are going to load leap seconds descriptions that are shared
@@ -1730,7 +1669,7 @@
     goto end_with_close;
   }
 
-  table= tables_buff[0].table;
+  table= tz_tables[0].table;
   /*
     It is OK to ignore ha_index_init()/ha_index_end() return values since
     mysql.time_zone* tables are MyISAM and these operations always succeed
@@ -1787,7 +1726,12 @@
   if (default_tzname)
   {
     String tmp_tzname2(default_tzname, &my_charset_latin1);
-    if (!(global_system_variables.time_zone= my_tz_find(&tmp_tzname2, tables)))
+    /*
+      Time zone tables may be open here, and my_tz_find() may open
+      most of them once more, but this is OK for system tables open
+      for READ.
+    */
+    if (!(global_system_variables.time_zone= my_tz_find(thd, &tmp_tzname2)))
     {
       sql_print_error("Fatal error: Illegal or unknown default time zone '%s'",
                       default_tzname);
@@ -1796,8 +1740,11 @@
   }
 
 end_with_close:
-  thd->version--; /* Force close to free memory */
-  close_thread_tables(thd);
+  if (time_zone_tables_exist)
+  {
+    thd->version--; /* Force close to free memory */
+    close_system_tables(thd, &open_tables_state_backup);
+  }
 
 end_with_cleanup:
 
@@ -1906,7 +1853,6 @@
   */
   table= tz_tables->table;
   tz_tables= tz_tables->next_local;
-  table->use_all_columns();
   table->field[0]->store(tz_name->ptr(), tz_name->length(),
                          &my_charset_latin1);
   /*
@@ -1939,7 +1885,6 @@
     using the only index in this table).
   */
   table= tz_tables->table;
-  table->use_all_columns();
   tz_tables= tz_tables->next_local;
   table->field[0]->store((longlong) tzid, TRUE);
   (void)table->file->ha_index_init(0, 1);
@@ -1967,7 +1912,6 @@
     Right - using special index.
   */
   table= tz_tables->table;
-  table->use_all_columns();
   tz_tables= tz_tables->next_local;
   table->field[0]->store((longlong) tzid, TRUE);
   (void)table->file->ha_index_init(0, 1);
@@ -2040,7 +1984,6 @@
     in ascending order by index scan also satisfies us.
   */
   table= tz_tables->table; 
-  table->use_all_columns();
   table->field[0]->store((longlong) tzid, TRUE);
   (void)table->file->ha_index_init(0, 1);
 
@@ -2249,8 +2192,8 @@
 
   SYNOPSIS
     my_tz_find()
+      thd  - pointer to thread THD structure
       name - time zone specification
-      tz_tables - list of opened'n'locked time zone describing tables
 
   DESCRIPTION
     This function checks if name is one of time zones described in db,
@@ -2272,11 +2215,10 @@
     values as parameter without additional external check and this property
     is used by @@time_zone variable handling code).
 
-    It will perform lookup in system tables (mysql.time_zone*) if needed
-    using tz_tables as list of already opened tables (for info about this
-    list look at tz_load_from_open_tables() description). It won't perform
-    such lookup if no time zone describing tables were found during server
-    start up.
+    It will perform lookup in system tables (mysql.time_zone*),
+    opening and locking them, and closing afterwards. It won't perform
+    such lookup if no time zone describing tables were found during
+    server start up.
 
   RETURN VALUE
     Pointer to corresponding Time_zone object. 0 - in case of bad time zone
@@ -2284,7 +2226,7 @@
 
 */
 Time_zone *
-my_tz_find(const String * name, TABLE_LIST *tz_tables)
+my_tz_find(THD *thd, const String *name)
 {
   Tz_names_entry *tmp_tzname;
   Time_zone *result_tz= 0;
@@ -2292,8 +2234,6 @@
   DBUG_ENTER("my_tz_find");
   DBUG_PRINT("enter", ("time zone name='%s'",
                        name ? ((String *)name)->c_ptr_safe() : "NULL"));
-  DBUG_ASSERT(!time_zone_tables_exist || tz_tables ||
-              current_thd->slave_thread);
 
   if (!name)
     DBUG_RETURN(0);
@@ -2325,8 +2265,19 @@
                                                    (const byte *)name->ptr(),
                                                    name->length())))
       result_tz= tmp_tzname->tz;
-    else if (time_zone_tables_exist && tz_tables)
-      result_tz= tz_load_from_open_tables(name, tz_tables);
+    else if (time_zone_tables_exist)
+    {
+      TABLE_LIST tz_tables[MY_TZ_TABLES_COUNT];
+      Open_tables_state open_tables_state_backup;
+
+      tz_init_table_list(tz_tables);
+      if (!open_system_tables_for_read(thd, tz_tables,
+                                       &open_tables_state_backup))
+      {
+        result_tz= tz_load_from_open_tables(name, tz_tables);
+        close_system_tables(thd, &open_tables_state_backup);
+      }
+    }
   }
 
   VOID(pthread_mutex_unlock(&tz_LOCK));
@@ -2334,58 +2285,6 @@
   DBUG_RETURN(result_tz);
 }
 
-
-/*
-  A more standalone version of my_tz_find(): will open tz tables if needed.
-  This is so far only used by replication, where time zone setting does not
-  happen in the usual query context.
-
-  SYNOPSIS
-    my_tz_find_with_opening_tz_tables()
-      thd  - pointer to thread's THD structure
-      name - time zone specification
-
-  DESCRIPTION
-    This function tries to find a time zone which matches the named passed in
-    argument. If it fails, it will open time zone tables and re-try the
-    search.
-    This function is needed for the slave SQL thread, which does not do the
-    addition of time zone tables which is usually done during query parsing
-    (as time zone setting by slave does not happen in mysql_parse() but
-    before). So it needs to open tz tables by itself if needed.
-    See notes of my_tz_find() as they also apply here.
-
-  RETURN VALUE
-    Pointer to corresponding Time_zone object. 0 - in case of bad time zone
-    specification or other error.
-*/
-
-Time_zone *my_tz_find_with_opening_tz_tables(THD *thd, const String *name)
-{
-  Time_zone *tz;
-  DBUG_ENTER("my_tz_find_with_opening_tables");
-  DBUG_ASSERT(thd);
-  DBUG_ASSERT(thd->slave_thread); // intended for use with slave thread only
-
-  if (!(tz= my_tz_find(name, 0)) && time_zone_tables_exist)
-  {
-    /*
-      Probably we have not loaded this time zone yet so let us look it up in
-      our time zone tables. Note that if we don't have tz tables on this
-      slave, we don't even try.
-    */
-    TABLE_LIST tables[MY_TZ_TABLES_COUNT];
-    TABLE_LIST *dummy;
-    TABLE_LIST **dummyp= &dummy;
-    tz_init_table_list(tables, &dummyp);
-    if (simple_open_n_lock_tables(thd, tables))
-      DBUG_RETURN(0);
-    tz= my_tz_find(name, tables);
-    /* We need to close tables _now_ to not pollute coming query */
-    close_thread_tables(thd);
-  }
-  DBUG_RETURN(tz);
-}
 
 #endif /* !defined(TESTTIME) && !defined(TZINFO2SQL) */
 

--- 1.283/mysql-test/mysql-test-run.pl	2007-03-08 16:56:05 +03:00
+++ 1.284/mysql-test/mysql-test-run.pl	2007-03-20 00:37:24 +03:00
@@ -902,7 +902,7 @@
   # --------------------------------------------------------------------------
   if ( $opt_with_ndbcluster and !$opt_bench)
   {
-    mtr_error("Can only use --with-ndbcluster togheter with --bench");
+    mtr_error("Can only use --with-ndbcluster together with --bench");
   }
 
   if ( $opt_ndbconnectstring )

--- 1.161/include/my_global.h	2007-03-17 13:19:17 +03:00
+++ 1.162/include/my_global.h	2007-03-20 00:37:24 +03:00
@@ -1496,4 +1496,10 @@
 #include <new>
 #endif
 
+/* Length of decimal number represented by INT32. */
+#define MY_INT32_NUM_DECIMAL_DIGITS 11
+
+/* Length of decimal number represented by INT64. */
+#define MY_INT64_NUM_DECIMAL_DIGITS 21
+
 #endif /* my_global_h */

--- 1.85/mysql-test/r/query_cache.result	2007-02-14 16:46:09 +03:00
+++ 1.86/mysql-test/r/query_cache.result	2007-03-20 00:37:25 +03:00
@@ -1325,4 +1325,27 @@
 insert into t1(c1) select c1 from v1;
 drop table t1, t2, t3;
 drop view v1;
+create table t1(c1 int);
+insert into t1 values(1),(10),(100);
+select * from t1;
+c1
+1
+10
+100
+select * from t1;
+c1
+1
+10
+100
+select * from t1;
+c1
+1
+10
+100
+select * from t1;
+c1
+1
+10
+100
+drop table t1;
 set global query_cache_size=0;

--- 1.18/mysql-test/t/grant_cache.test	2007-02-26 13:49:23 +03:00
+++ 1.19/mysql-test/t/grant_cache.test	2007-03-20 00:37:25 +03:00
@@ -1,6 +1,8 @@
 # Grant tests not performed with embedded server
 -- source include/not_embedded.inc
 -- source include/have_query_cache.inc
+# See at the end of the test why we disable the ps protocol (*)
+-- disable_ps_protocol
 
 --source include/add_anonymous_users.inc
 
@@ -157,3 +159,27 @@
 
 
 # End of 4.1 tests
+
+# (*) Why we disable the ps protocol: because in normal protocol,
+# a SELECT failing due to insufficient privileges increments
+# Qcache_not_cached, while in ps-protocol, no.
+# In detail: in normal protocol,
+# the "access denied" errors on SELECT are issued at (stack trace):
+# mysql_parse/mysql_execute_command/execute_sqlcom_select/handle_select/
+# mysql_select/JOIN::prepare/setup_wild/insert_fields/
+# check_grant_all_columns/my_error/my_message_sql, which then calls
+# push_warning/query_cache_abort: at this moment,
+# query_cache_store_query() has been called, so query exists in cache,
+# so thd->net.query_cache_query!=NULL, so query_cache_abort() removes
+# the query from cache, which causes a query_cache.refused++ (thus,
+# a Qcache_not_cached++).
+# While in ps-protocol, the error is issued at prepare time;
+# for this mysql_test_select() is called, not execute_sqlcom_select()
+# (and that also leads to JOIN::prepare/etc). Thus, as
+# query_cache_store_query() has not been called,
+# thd->net.query_cache_query==NULL, so query_cache_abort() does nothing:
+# Qcache_not_cached is not incremented.
+# As this test prints Qcache_not_cached after SELECT failures,
+# we cannot enable this test in ps-protocol.
+
+--enable_ps_protocol

--- 1.66/mysql-test/t/query_cache.test	2007-02-14 16:46:09 +03:00
+++ 1.67/mysql-test/t/query_cache.test	2007-03-20 00:37:25 +03:00
@@ -907,4 +907,24 @@
 insert into t1(c1) select c1 from v1;
 drop table t1, t2, t3;
 drop view v1;
+
+
+#
+# If running with --ps-protocol:
+# see if a query from the text protocol is served with results cached
+# from a query which used the binary (which would be wrong, results
+# are in different formats); if that happens, the results will
+# be incorrect and the test will fail.
+#
+
+create table t1(c1 int);
+insert into t1 values(1),(10),(100);
+select * from t1;
+-- disable_ps_protocol
+select * from t1;
+select * from t1;
+-- enable_ps_protocol
+select * from t1;
+drop table t1;
+
 set global query_cache_size=0;

--- 1.221/sql/set_var.cc	2007-03-08 16:47:53 +03:00
+++ 1.222/sql/set_var.cc	2007-03-20 00:37:31 +03:00
@@ -2750,8 +2750,8 @@
   thd->variables.character_set_results= character_set_results;
   thd->variables.collation_connection= collation_connection;
   thd->update_charset();
-  thd->protocol_simple.init(thd);
-  thd->protocol_prep.init(thd);
+  thd->protocol_text.init(thd);
+  thd->protocol_binary.init(thd);
   return 0;
 }
 
@@ -2880,8 +2880,7 @@
   String str(buff, sizeof(buff), &my_charset_latin1);
   String *res= var->value->val_str(&str);
 
-  if (!(var->save_result.time_zone=
-        my_tz_find(res, thd->lex->time_zone_tables_used)))
+  if (!(var->save_result.time_zone= my_tz_find(thd, res)))
   {
     my_error(ER_UNKNOWN_TIME_ZONE, MYF(0), res ? res->c_ptr() : "NULL");
     return 1;
@@ -2942,8 +2941,7 @@
        We are guaranteed to find this time zone since its existence
        is checked during start-up.
      */
-     global_system_variables.time_zone=
-       my_tz_find(&str, thd->lex->time_zone_tables_used);
+     global_system_variables.time_zone= my_tz_find(thd, &str);
    }
    else
      global_system_variables.time_zone= my_tz_SYSTEM;
@@ -4013,7 +4011,7 @@
   DBUG_ENTER("sys_var_event_scheduler::update");
   if (Events::opt_event_scheduler == Events::EVENTS_DISABLED)
   {
-    my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--event-scheduler=DISABLED");
+    my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--event-scheduler=DISABLED or --skip-grant-tables");
     DBUG_RETURN(TRUE);
   }
 

--- 1.54.1.1/scripts/mysql_fix_privilege_tables.sql	2007-03-16 17:31:03 +03:00
+++ 1.60/scripts/mysql_system_tables_fix.sql	2007-03-20 00:37:25 +03:00
@@ -1,6 +1,7 @@
-# This script converts any old privilege tables to privilege tables suitable
-# for this version of MySQL
-# You can safely ignore all 'Duplicate column' and 'Unknown column' errors"
+# This part converts any old privilege tables to privilege tables suitable
+# for current version of MySQL
+
+# You can safely ignore all 'Duplicate column' and 'Unknown column' errors
 # because these just mean that your tables are already up to date.
 # This script is safe to run even if your tables are already up to date!
 
@@ -11,20 +12,6 @@
 set sql_mode='';
 set storage_engine=MyISAM;
 
-CREATE TABLE IF NOT EXISTS func (
-  name char(64) binary DEFAULT '' NOT NULL,
-  ret tinyint(1) DEFAULT '0' NOT NULL,
-  dl char(128) DEFAULT '' NOT NULL,
-  type enum ('function','aggregate') COLLATE utf8_general_ci NOT NULL,
-  PRIMARY KEY (name)
-) CHARACTER SET utf8 COLLATE utf8_bin;
-
-CREATE TABLE IF NOT EXISTS plugin (
-  name char(64) binary DEFAULT '' NOT NULL,
-  dl char(128) DEFAULT '' NOT NULL,
-  PRIMARY KEY (name)
-) CHARACTER SET utf8 COLLATE utf8_bin;
-
 ALTER TABLE user add File_priv enum('N','Y') COLLATE utf8_general_ci NOT NULL;
 
 # Detect whether or not we had the Grant_priv column
@@ -42,7 +29,7 @@
 
 #
 # The second alter changes ssl_type to new 4.0.2 format
-# Adding columns needed by GRANT .. REQUIRE (openssl)"
+# Adding columns needed by GRANT .. REQUIRE (openssl)
 
 ALTER TABLE user
 ADD ssl_type enum('','ANY','X509', 'SPECIFIED') COLLATE utf8_general_ci NOT NULL,
@@ -54,21 +41,6 @@
 #
 # tables_priv
 #
-CREATE TABLE IF NOT EXISTS tables_priv (
-  Host char(60) binary DEFAULT '' NOT NULL,
-  Db char(64) binary DEFAULT '' NOT NULL,
-  User char(16) binary DEFAULT '' NOT NULL,
-  Table_name char(64) binary DEFAULT '' NOT NULL,
-  Grantor char(77) DEFAULT '' NOT NULL,
-  Timestamp timestamp(14),
-  Table_priv set('Select','Insert','Update','Delete','Create',
-                 'Drop','Grant','References','Index','Alter')
-    COLLATE utf8_general_ci DEFAULT '' NOT NULL,
-  Column_priv set('Select','Insert','Update','References')
-    COLLATE utf8_general_ci DEFAULT '' NOT NULL,
-  PRIMARY KEY (Host,Db,User,Table_name)
-) CHARACTER SET utf8 COLLATE utf8_bin;
-# Fix collation of set fields
 ALTER TABLE tables_priv
   ADD KEY Grantor (Grantor);
 
@@ -93,16 +65,6 @@
 #
 # columns_priv
 #
-CREATE TABLE IF NOT EXISTS columns_priv (
-  Host char(60) DEFAULT '' NOT NULL,
-  Db char(64) DEFAULT '' NOT NULL,
-  User char(16) DEFAULT '' NOT NULL,
-  Table_name char(64) DEFAULT '' NOT NULL,
-  Column_name char(64) DEFAULT '' NOT NULL,
-  Timestamp timestamp(14),
-  Column_priv set('Select','Insert','Update','References') COLLATE utf8_general_ci DEFAULT '' NOT NULL,
-  PRIMARY KEY (Host,Db,User,Table_name,Column_name)
-) CHARACTER SET utf8 COLLATE utf8_bin;
 #
 # Name change of Type -> Column_priv from MySQL 3.22.12
 #
@@ -131,7 +93,7 @@
 ALTER TABLE func add type enum ('function','aggregate') COLLATE utf8_general_ci NOT NULL;
 
 #
-#  Change the user,db and host tables to MySQL 4.0 format
+#  Change the user,db and host tables to current format
 #
 
 # Detect whether we had Show_db_priv
@@ -154,6 +116,7 @@
 
 #  Add fields that can be used to limit number of questions and connections
 #  for some users.
+
 ALTER TABLE user
 ADD max_questions int(11) NOT NULL DEFAULT 0 AFTER x509_subject,
 ADD max_updates   int(11) unsigned NOT NULL DEFAULT 0 AFTER max_questions,
@@ -254,7 +217,7 @@
 
 #
 # Detect whether we had Create_view_priv
-# 
+#
 SET @hadCreateViewPriv:=0;
 SELECT @hadCreateViewPriv:=1 FROM user WHERE Create_view_priv LIKE '%';
 
@@ -331,7 +294,7 @@
 UPDATE host SET Create_routine_priv=Create_priv, Alter_routine_priv=Alter_priv, Execute_priv=Select_priv where @hadCreateRoutinePriv = 0;
 
 #
-# Add max_user_connections resource limit 
+# Add max_user_connections resource limit
 #
 ALTER TABLE user ADD max_user_connections int(11) unsigned DEFAULT '0' NOT NULL AFTER max_connections;
 
@@ -348,22 +311,9 @@
   WHERE @hadCreateUserPriv = 0 AND
         (user.Grant_priv = 'Y' OR db.Grant_priv = 'Y');
 
---
--- procs_priv
---
-CREATE TABLE IF NOT EXISTS procs_priv (
-  Host char(60) binary DEFAULT '' NOT NULL,
-  Db char(64) binary DEFAULT '' NOT NULL,
-  User char(16) binary DEFAULT '' NOT NULL,
-  Routine_name char(64) binary DEFAULT '' NOT NULL,
-  Routine_type enum('FUNCTION','PROCEDURE') NOT NULL,
-  Grantor char(77) DEFAULT '' NOT NULL,
-  Proc_priv set('Execute','Alter Routine','Grant')
-    COLLATE utf8_general_ci DEFAULT '' NOT NULL,
-  Timestamp timestamp(14),
-  PRIMARY KEY (Host, Db, User, Routine_name, Routine_type),
-  KEY Grantor (Grantor)
-) CHARACTER SET utf8 COLLATE utf8_bin comment='Procedure privileges';
+#
+# procs_priv
+#
 
 ALTER TABLE procs_priv
   ENGINE=MyISAM,
@@ -380,159 +330,9 @@
 ALTER TABLE procs_priv
   MODIFY Timestamp timestamp(14) AFTER Proc_priv;
 
---
--- servers 
---
-CREATE TABLE servers (
-  Server_name char(64) NOT NULL DEFAULT '',
-  Host char(64) NOT NULL DEFAULT '',
-  Db char(64) NOT NULL DEFAULT '',
-  Username char(64) NOT NULL DEFAULT '',
-  Password char(64) NOT NULL DEFAULT '',
-  Port INT(4) NOT NULL DEFAULT '0',
-  Socket char(64) NOT NULL DEFAULT '',
-  Wrapper char(64) NOT NULL DEFAULT '',
-  Owner char(64) NOT NULL DEFAULT '',
-  PRIMARY KEY (Server_name))
-  CHARACTER SET utf8 comment='MySQL Foreign Servers table';
-
---
--- help_topic
---
-CREATE TABLE IF NOT EXISTS help_topic (
-help_topic_id int unsigned not null,
-name varchar(64) not null,
-help_category_id smallint unsigned not null,
-description text not null,
-example text not null,
-url varchar(128) not null,
-primary key (help_topic_id), unique index (name)
-) CHARACTER SET utf8 comment='help topics';
-
-CREATE TABLE IF NOT EXISTS help_category (
-help_category_id smallint unsigned not null,
-name varchar(64) not null,
-parent_category_id smallint unsigned null,
-url varchar(128) not null,
-primary key (help_category_id),
-unique index (name)
-) CHARACTER SET utf8 comment='help categories';
-
-CREATE TABLE IF NOT EXISTS help_relation (
-help_topic_id int unsigned not null references help_topic,
-help_keyword_id  int unsigned not null references help_keyword,
-primary key (help_keyword_id, help_topic_id)
-) CHARACTER SET utf8 comment='keyword-topic relation';
-
-CREATE TABLE IF NOT EXISTS help_keyword (
-help_keyword_id int unsigned not null,
-name varchar(64) not null,
-primary key (help_keyword_id),
-unique index (name)
-) CHARACTER SET utf8 comment='help keywords';
-
-#
-# Create missing time zone related tables
-#
-
-CREATE TABLE IF NOT EXISTS time_zone_name (
-Name char(64) NOT NULL,   
-Time_zone_id int  unsigned NOT NULL,
-PRIMARY KEY Name (Name) 
-) CHARACTER SET utf8 comment='Time zone names';
-
-CREATE TABLE IF NOT EXISTS time_zone (
-Time_zone_id int unsigned NOT NULL auto_increment,
-Use_leap_seconds  enum('Y','N') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL,
-PRIMARY KEY TzId (Time_zone_id) 
-) CHARACTER SET utf8 comment='Time zones';
-# Make enum field case-insensitive
-ALTER TABLE time_zone
-  MODIFY Use_leap_seconds enum('Y','N') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL;
-
-CREATE TABLE IF NOT EXISTS time_zone_transition (
-Time_zone_id int unsigned NOT NULL,
-Transition_time bigint signed NOT NULL,   
-Transition_type_id int unsigned NOT NULL,
-PRIMARY KEY TzIdTranTime (Time_zone_id, Transition_time) 
-) CHARACTER SET utf8 comment='Time zone transitions';
-
-CREATE TABLE IF NOT EXISTS time_zone_transition_type (
-Time_zone_id int unsigned NOT NULL,
-Transition_type_id int unsigned NOT NULL,
-Offset int signed DEFAULT 0 NOT NULL,
-Is_DST tinyint unsigned DEFAULT 0 NOT NULL,
-Abbreviation char(8) DEFAULT '' NOT NULL,
-PRIMARY KEY TzIdTrTId (Time_zone_id, Transition_type_id) 
-) CHARACTER SET utf8 comment='Time zone transition types';
-
-CREATE TABLE IF NOT EXISTS time_zone_leap_second (
-Transition_time bigint signed NOT NULL,
-Correction int signed NOT NULL,   
-PRIMARY KEY TranTime (Transition_time) 
-) CHARACTER SET utf8 comment='Leap seconds information for time zones';
-
-
-#
-# Create proc table if it does not exists
-#
-
-CREATE TABLE IF NOT EXISTS proc (
-  db                char(64) collate utf8_bin DEFAULT '' NOT NULL,
-  name              char(64) DEFAULT '' NOT NULL,
-  type              enum('FUNCTION','PROCEDURE') NOT NULL,
-  specific_name     char(64) DEFAULT '' NOT NULL,
-  language          enum('SQL') DEFAULT 'SQL' NOT NULL,
-  sql_data_access   enum('CONTAINS_SQL',
-                         'NO_SQL',
-                         'READS_SQL_DATA',
-                         'MODIFIES_SQL_DATA'
-                    ) DEFAULT 'CONTAINS_SQL' NOT NULL,
-  is_deterministic  enum('YES','NO') DEFAULT 'NO' NOT NULL,
-  security_type     enum('INVOKER','DEFINER') DEFAULT 'DEFINER' NOT NULL,
-  param_list        blob DEFAULT '' NOT NULL,
-  returns           char(64) DEFAULT '' NOT NULL,
-  body              longblob DEFAULT '' NOT NULL,
-  definer           char(77) collate utf8_bin DEFAULT '' NOT NULL,
-  created           timestamp,
-  modified          timestamp,
-  sql_mode          set(
-                        'REAL_AS_FLOAT',
-                        'PIPES_AS_CONCAT',
-                        'ANSI_QUOTES',
-                        'IGNORE_SPACE',
-                        'NOT_USED',
-                        'ONLY_FULL_GROUP_BY',
-                        'NO_UNSIGNED_SUBTRACTION',
-                        'NO_DIR_IN_CREATE',
-                        'POSTGRESQL',
-                        'ORACLE',
-                        'MSSQL',
-                        'DB2',
-                        'MAXDB',
-                        'NO_KEY_OPTIONS',
-                        'NO_TABLE_OPTIONS',
-                        'NO_FIELD_OPTIONS',
-                        'MYSQL323',
-                        'MYSQL40',
-                        'ANSI',
-                        'NO_AUTO_VALUE_ON_ZERO',
-                        'NO_BACKSLASH_ESCAPES',
-                        'STRICT_TRANS_TABLES',
-                        'STRICT_ALL_TABLES',
-                        'NO_ZERO_IN_DATE',
-                        'NO_ZERO_DATE',
-                        'INVALID_DATES',
-                        'ERROR_FOR_DIVISION_BY_ZERO',
-                        'TRADITIONAL',
-                        'NO_AUTO_CREATE_USER',
-                        'HIGH_NOT_PRECEDENCE'
-                    ) DEFAULT '' NOT NULL,
-  comment           char(64) collate utf8_bin DEFAULT '' NOT NULL,
-  PRIMARY KEY (db,name,type)
-) engine=MyISAM
-  character set utf8
-  comment='Stored Procedures';
+#
+# proc
+#
 
 # Correct the name fields to not binary, and expand sql_data_access
 ALTER TABLE proc MODIFY name char(64) DEFAULT '' NOT NULL,

--- 1.256/mysql-test/r/sp.result	2007-03-09 12:39:49 +03:00
+++ 1.257/mysql-test/r/sp.result	2007-03-20 00:42:03 +03:00
@@ -5617,6 +5617,32 @@
 Called B
 drop procedure proc_21462_a|
 drop procedure proc_21462_b|
+DROP PROCEDURE IF EXISTS p1|
+DROP VIEW IF EXISTS v1, v2|
+DROP TABLE IF EXISTS t3, t4|
+CREATE TABLE t3 (t3_id INT)|
+INSERT INTO t3 VALUES (0)|
+INSERT INTO t3 VALUES (1)|
+CREATE TABLE t4 (t4_id INT)|
+INSERT INTO t4 VALUES (2)|
+CREATE VIEW v1 AS
+SELECT t3.t3_id, t4.t4_id
+FROM t3 JOIN t4 ON t3.t3_id = 0|
+CREATE VIEW v2 AS
+SELECT t3.t3_id AS t3_id_1, v1.t3_id AS t3_id_2, v1.t4_id
+FROM t3 LEFT JOIN v1 ON t3.t3_id = 0|
+CREATE PROCEDURE p1() SELECT * FROM v2|
+CALL p1()|
+t3_id_1	t3_id_2	t4_id
+0	0	2
+1	NULL	NULL
+CALL p1()|
+t3_id_1	t3_id_2	t4_id
+0	0	2
+1	NULL	NULL
+DROP PROCEDURE p1|
+DROP VIEW v1, v2|
+DROP TABLE t3, t4|
 End of 5.0 tests
 Begin of 5.1 tests
 drop function if exists pi;
@@ -5857,6 +5883,171 @@
 1500
 drop function func_8407_a|
 drop function func_8407_b|
+drop table if exists table_26503|
+drop procedure if exists proc_26503_ok_1|
+drop procedure if exists proc_26503_ok_2|
+drop procedure if exists proc_26503_ok_3|
+drop procedure if exists proc_26503_ok_4|
+create table table_26503(a int unique)|
+create procedure proc_26503_ok_1(v int)
+begin
+declare i int default 5;
+declare continue handler for sqlexception
+begin
+select 'caught something';
+retry:
+while i > 0 do
+begin
+set i = i - 1;
+select 'looping', i;
+iterate retry;
+select 'dead code';
+end;
+end while retry;
+select 'leaving handler';
+end;
+select 'do something';
+insert into table_26503 values (v);
+select 'do something again';
+insert into table_26503 values (v);
+end|
+create procedure proc_26503_ok_2(v int)
+begin
+declare i int default 5;
+declare continue handler for sqlexception
+begin
+select 'caught something';
+retry:
+while i > 0 do
+begin
+set i = i - 1;
+select 'looping', i;
+leave retry;
+select 'dead code';
+end;
+end while;
+select 'leaving handler';
+end;
+select 'do something';
+insert into table_26503 values (v);
+select 'do something again';
+insert into table_26503 values (v);
+end|
+create procedure proc_26503_ok_3(v int)
+begin
+declare i int default 5;
+retry:
+begin
+declare continue handler for sqlexception
+begin
+select 'caught something';
+retry:
+while i > 0 do
+begin
+set i = i - 1;
+select 'looping', i;
+iterate retry;
+select 'dead code';
+end;
+end while retry;
+select 'leaving handler';
+end;
+select 'do something';
+insert into table_26503 values (v);
+select 'do something again';
+insert into table_26503 values (v);
+end;
+end|
+create procedure proc_26503_ok_4(v int)
+begin
+declare i int default 5;
+retry:
+begin
+declare continue handler for sqlexception
+begin
+select 'caught something';
+retry:
+while i > 0 do
+begin
+set i = i - 1;
+select 'looping', i;
+leave retry;
+select 'dead code';
+end;
+end while;
+select 'leaving handler';
+end;
+select 'do something';
+insert into table_26503 values (v);
+select 'do something again';
+insert into table_26503 values (v);
+end;
+end|
+call proc_26503_ok_1(1)|
+do something
+do something
+do something again
+do something again
+caught something
+caught something
+looping	i
+looping	4
+looping	i
+looping	3
+looping	i
+looping	2
+looping	i
+looping	1
+looping	i
+looping	0
+leaving handler
+leaving handler
+call proc_26503_ok_2(2)|
+do something
+do something
+do something again
+do something again
+caught something
+caught something
+looping	i
+looping	4
+leaving handler
+leaving handler
+call proc_26503_ok_3(3)|
+do something
+do something
+do something again
+do something again
+caught something
+caught something
+looping	i
+looping	4
+looping	i
+looping	3
+looping	i
+looping	2
+looping	i
+looping	1
+looping	i
+looping	0
+leaving handler
+leaving handler
+call proc_26503_ok_4(4)|
+do something
+do something
+do something again
+do something again
+caught something
+caught something
+looping	i
+looping	4
+leaving handler
+leaving handler
+drop table table_26503|
+drop procedure proc_26503_ok_1|
+drop procedure proc_26503_ok_2|
+drop procedure proc_26503_ok_3|
+drop procedure proc_26503_ok_4|
 DROP FUNCTION IF EXISTS bug25373|
 CREATE FUNCTION bug25373(p1 INTEGER) RETURNS INTEGER
 LANGUAGE SQL DETERMINISTIC

--- 1.223/mysql-test/t/sp.test	2007-03-09 12:39:37 +03:00
+++ 1.224/mysql-test/t/sp.test	2007-03-20 00:42:03 +03:00
@@ -6564,6 +6564,46 @@
 drop procedure proc_21462_a|
 drop procedure proc_21462_b|
 
+
+#
+# BUG#20492: Subsequent calls to stored procedure yeild incorrect
+# result if join is used 
+#
+# Optimized ON expression in join wasn't properly saved for reuse.
+#
+--disable_warnings
+DROP PROCEDURE IF EXISTS p1|
+DROP VIEW IF EXISTS v1, v2|
+DROP TABLE IF EXISTS t3, t4|
+--enable_warnings
+
+CREATE TABLE t3 (t3_id INT)|
+
+INSERT INTO t3 VALUES (0)|
+INSERT INTO t3 VALUES (1)|
+
+CREATE TABLE t4 (t4_id INT)|
+
+INSERT INTO t4 VALUES (2)|
+
+CREATE VIEW v1 AS
+SELECT t3.t3_id, t4.t4_id
+FROM t3 JOIN t4 ON t3.t3_id = 0|
+
+CREATE VIEW v2 AS
+SELECT t3.t3_id AS t3_id_1, v1.t3_id AS t3_id_2, v1.t4_id
+FROM t3 LEFT JOIN v1 ON t3.t3_id = 0|
+
+CREATE PROCEDURE p1() SELECT * FROM v2|
+
+# Results should not differ.
+CALL p1()|
+CALL p1()|
+
+DROP PROCEDURE p1|
+DROP VIEW v1, v2|
+DROP TABLE t3, t4|
+
 --echo End of 5.0 tests
 
 --echo Begin of 5.1 tests
@@ -6826,6 +6866,141 @@
 
 drop function func_8407_a|
 drop function func_8407_b|
+
+#
+# Bug#26503 (Illegal SQL exception handler code causes the server to crash)
+#
+
+--disable_warnings
+drop table if exists table_26503|
+drop procedure if exists proc_26503_ok_1|
+drop procedure if exists proc_26503_ok_2|
+drop procedure if exists proc_26503_ok_3|
+drop procedure if exists proc_26503_ok_4|
+--enable_warnings
+
+create table table_26503(a int unique)|
+
+create procedure proc_26503_ok_1(v int)
+begin
+  declare i int default 5;
+
+  declare continue handler for sqlexception
+  begin
+    select 'caught something';
+    retry:
+    while i > 0 do
+      begin
+        set i = i - 1;
+        select 'looping', i;
+        iterate retry;
+        select 'dead code';
+      end;
+    end while retry;
+    select 'leaving handler';
+  end;
+
+  select 'do something';
+  insert into table_26503 values (v);
+  select 'do something again';
+  insert into table_26503 values (v);
+end|
+
+create procedure proc_26503_ok_2(v int)
+begin
+  declare i int default 5;
+
+  declare continue handler for sqlexception
+  begin
+    select 'caught something';
+    retry:
+    while i > 0 do
+      begin
+        set i = i - 1;
+        select 'looping', i;
+        leave retry;
+        select 'dead code';
+      end;
+    end while;
+    select 'leaving handler';
+  end;
+
+  select 'do something';
+  insert into table_26503 values (v);
+  select 'do something again';
+  insert into table_26503 values (v);
+end|
+
+## The outer retry label should not prevent using the inner label.
+
+create procedure proc_26503_ok_3(v int)
+begin
+  declare i int default 5;
+
+retry:
+  begin
+    declare continue handler for sqlexception
+    begin
+      select 'caught something';
+      retry:
+      while i > 0 do
+        begin
+          set i = i - 1;
+          select 'looping', i;
+          iterate retry;
+          select 'dead code';
+        end;
+      end while retry;
+      select 'leaving handler';
+    end;
+
+    select 'do something';
+    insert into table_26503 values (v);
+    select 'do something again';
+    insert into table_26503 values (v);
+  end;
+end|
+
+## The outer retry label should not prevent using the inner label.
+
+create procedure proc_26503_ok_4(v int)
+begin
+  declare i int default 5;
+
+retry:
+  begin
+    declare continue handler for sqlexception
+    begin
+      select 'caught something';
+      retry:
+      while i > 0 do
+        begin
+          set i = i - 1;
+          select 'looping', i;
+          leave retry;
+          select 'dead code';
+        end;
+      end while;
+      select 'leaving handler';
+    end;
+
+    select 'do something';
+    insert into table_26503 values (v);
+    select 'do something again';
+    insert into table_26503 values (v);
+  end;
+end|
+
+call proc_26503_ok_1(1)|
+call proc_26503_ok_2(2)|
+call proc_26503_ok_3(3)|
+call proc_26503_ok_4(4)|
+
+drop table table_26503|
+drop procedure proc_26503_ok_1|
+drop procedure proc_26503_ok_2|
+drop procedure proc_26503_ok_3|
+drop procedure proc_26503_ok_4|
 
 #
 # Bug#25373: Stored functions wasn't compared correctly which leads to a wrong

--- 1.141/sql/sp.cc	2007-03-17 02:13:18 +03:00
+++ 1.142/sql/sp.cc	2007-03-20 00:37:31 +03:00
@@ -69,24 +69,6 @@
 
 
 /*
-  Close mysql.proc, opened with open_proc_table_for_read().
-
-  SYNOPSIS
-    close_proc_table()
-      thd     Thread context
-      backup  Pointer to Open_tables_state instance which holds
-              information about tables which were open before we
-              decided to access mysql.proc.
-*/
-
-void close_proc_table(THD *thd, Open_tables_state *backup)
-{
-  close_thread_tables(thd);
-  thd->restore_backup_open_tables_state(backup);
-}
-
-
-/*
   Open the mysql.proc table for read.
 
   SYNOPSIS
@@ -96,13 +78,6 @@
               currently open tables will be saved, and from which will be
               restored when we will end work with mysql.proc.
 
-  NOTES
-    Thanks to restrictions which we put on opening and locking of
-    this table for writing, we can open and lock it for reading
-    even when we already have some other tables open and locked.
-    One must call close_proc_table() to close table opened with
-    this call.
-
   RETURN
     0	Error
     #	Pointer to TABLE object of mysql.proc
@@ -110,38 +85,18 @@
 
 TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
 {
-  TABLE_LIST tables;
-  TABLE *table;
-  bool not_used;
-  DBUG_ENTER("open_proc_table");
-
-  thd->reset_n_backup_open_tables_state(backup);
-
-  bzero((char*) &tables, sizeof(tables));
-  tables.db= (char*) "mysql";
-  tables.table_name= tables.alias= (char*)"proc";
-  if (!(table= open_table(thd, &tables, thd->mem_root, &not_used,
-                          MYSQL_LOCK_IGNORE_FLUSH)))
-  {
-    thd->restore_backup_open_tables_state(backup);
-    DBUG_RETURN(0);
-  }
-  table->use_all_columns();
+  DBUG_ENTER("open_proc_table_for_read");
 
-  DBUG_ASSERT(table->s->system_table);
+  TABLE_LIST table;
+  bzero((char*) &table, sizeof(table));
+  table.db= (char*) "mysql";
+  table.table_name= table.alias= (char*)"proc";
+  table.lock_type= TL_READ;
 
-  table->reginfo.lock_type= TL_READ;
-  /*
-    We have to ensure we are not blocked by a flush tables, as this
-    could lead to a deadlock if we have other tables opened.
-  */
-  if (!(thd->lock= mysql_lock_tables(thd, &table, 1,
-                                     MYSQL_LOCK_IGNORE_FLUSH, &not_used)))
-  {
-    close_proc_table(thd, backup);
+  if (!open_system_tables_for_read(thd, &table, backup))
+    DBUG_RETURN(table.table);
+  else
     DBUG_RETURN(0);
-  }
-  DBUG_RETURN(table);
 }
 
 
@@ -162,20 +117,15 @@
 
 static TABLE *open_proc_table_for_update(THD *thd)
 {
-  TABLE_LIST tables;
-  TABLE *table;
-  DBUG_ENTER("open_proc_table");
-
-  bzero((char*) &tables, sizeof(tables));
-  tables.db= (char*) "mysql";
-  tables.table_name= tables.alias= (char*)"proc";
-  tables.lock_type= TL_WRITE;
+  DBUG_ENTER("open_proc_table_for_update");
 
-  table= open_ltable(thd, &tables, TL_WRITE);
-  if (table)
-    table->use_all_columns();
+  TABLE_LIST table;
+  bzero((char*) &table, sizeof(table));
+  table.db= (char*) "mysql";
+  table.table_name= table.alias= (char*)"proc";
+  table.lock_type= TL_WRITE;
 
-  DBUG_RETURN(table);
+  DBUG_RETURN(open_system_table_for_update(thd, &table));
 }
 
 
@@ -363,7 +313,7 @@
   chistics.comment.str= ptr;
   chistics.comment.length= length;
 
-  close_proc_table(thd, &open_tables_state_backup);
+  close_system_tables(thd, &open_tables_state_backup);
   table= 0;
 
   ret= db_load_routine(thd, type, name, sphp,
@@ -372,7 +322,7 @@
                        
  done:
   if (table)
-    close_proc_table(thd, &open_tables_state_backup);
+    close_system_tables(thd, &open_tables_state_backup);
   DBUG_RETURN(ret);
 }
 
@@ -1146,7 +1096,7 @@
   {
     if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK)
       ret= SP_KEY_NOT_FOUND;
-    close_proc_table(thd, &open_tables_state_backup);
+    close_system_tables(thd, &open_tables_state_backup);
   }
   return ret;
 }

--- 1.259/sql/sp_head.cc	2007-03-15 11:55:11 +03:00
+++ 1.260/sql/sp_head.cc	2007-03-20 00:37:32 +03:00
@@ -490,7 +490,7 @@
 {
   DBUG_ENTER("sp_head::init");
 
-  lex->spcont= m_pcont= new sp_pcontext(NULL);
+  lex->spcont= m_pcont= new sp_pcontext();
 
   /*
     Altough trg_table_fields list is used only in triggers we init for all
@@ -1117,7 +1117,7 @@
       case SP_HANDLER_CONTINUE:
         thd->restore_active_arena(&execute_arena, &backup_arena);
         thd->set_n_backup_active_arena(&execute_arena, &backup_arena);
-        ctx->push_hstack(ip);
+        ctx->push_hstack(i->get_cont_dest());
         // Fall through
       default:
 	ip= hip;
@@ -2449,7 +2449,7 @@
   reinit_stmt_before_use(thd, m_lex);
 
   if (open_tables)
-    res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables, nextp);
+    res= instr->exec_open_and_lock_tables(thd, m_lex->query_tables);
 
   if (!res)
   {
@@ -2501,8 +2501,7 @@
   sp_instr class functions
 */
 
-int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables,
-                                        uint *nextp)
+int sp_instr::exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
 {
   int result;
 
@@ -2512,19 +2511,16 @@
   */
   if (check_table_access(thd, SELECT_ACL, tables, 0)
       || open_and_lock_tables(thd, tables))
-  {
-    get_cont_dest(nextp);
     result= -1;
-  }
   else
     result= 0;
 
   return result;
 }
 
-void sp_instr::get_cont_dest(uint *nextp)
+uint sp_instr::get_cont_dest()
 {
-  *nextp= m_ip+1;
+  return (m_ip+1);
 }
 
 
@@ -2717,9 +2713,9 @@
   sp_instr_opt_meta
 */
 
-void sp_instr_opt_meta::get_cont_dest(uint *nextp)
+uint sp_instr_opt_meta::get_cont_dest()
 {
-  *nextp= m_cont_dest;
+  return m_cont_dest;
 }
 
 
@@ -2811,7 +2807,6 @@
   if (! it)
   {
     res= -1;
-    *nextp = m_cont_dest;
   }
   else
   {
@@ -3380,7 +3375,6 @@
       spcont->clear_handler();
       thd->spcont= spcont;
     }
-    *nextp= m_cont_dest;        /* For continue handler */
   }
   else
     *nextp= m_ip+1;

--- 1.99/sql/sp_head.h	2007-03-08 02:02:32 +03:00
+++ 1.100/sql/sp_head.h	2007-03-20 00:37:32 +03:00
@@ -107,8 +107,6 @@
   /* Possible values of m_flags */
   enum {
     HAS_RETURN= 1,              // For FUNCTIONs only: is set if has RETURN
-    IN_SIMPLE_CASE= 2,          // Is set if parsing a simple CASE
-    IN_HANDLER= 4,              // Is set if the parser is in a handler body
     MULTI_RESULTS= 8,           // Is set if a procedure with SELECT(s)
     CONTAINS_DYNAMIC_SQL= 16,   // Is set if a procedure with PREPARE/EXECUTE
     IS_INVOKED= 32,             // Is set if this sp_head is being used
@@ -468,13 +466,15 @@
          thd        Thread handle
          nextp  OUT index of the next instruction to execute. (For most
                     instructions this will be the instruction following this
-                    one).
- 
-     RETURN 
-       0      on success, 
-       other  if some error occured
+                    one). Note that this parameter is undefined in case of
+                    errors, use get_cont_dest() to find the continuation
+                    instruction for CONTINUE error handlers.
+
+     RETURN
+       0      on success,
+       other  if some error occurred
   */
-  
+
   virtual int execute(THD *thd, uint *nextp) = 0;
 
   /**
@@ -482,22 +482,17 @@
     Open and lock the tables used by this statement, as a pre-requisite
     to execute the core logic of this instruction with
     <code>exec_core()</code>.
-    If this statement fails, the next instruction to execute is also returned.
-    This is useful when a user defined SQL continue handler needs to be
-    executed.
     @param thd the current thread
     @param tables the list of tables to open and lock
-    @param nextp the continuation instruction, returned to the caller if this
-    method fails.
     @return zero on success, non zero on failure.
   */
-  int exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables, uint *nextp);
+  int exec_open_and_lock_tables(THD *thd, TABLE_LIST *tables);
 
   /**
     Get the continuation destination of this instruction.
-    @param nextp the continuation destination (output)
+    @return the continuation destination
   */
-  virtual void get_cont_dest(uint *nextp);
+  virtual uint get_cont_dest();
 
   /*
     Execute core function of instruction after all preparations (e.g.
@@ -763,7 +758,7 @@
   virtual void set_destination(uint old_dest, uint new_dest)
     = 0;
 
-  virtual void get_cont_dest(uint *nextp);
+  virtual uint get_cont_dest();
 
 protected:
 

--- 1.207/sql/sql_prepare.cc	2007-03-15 14:10:58 +03:00
+++ 1.208/sql/sql_prepare.cc	2007-03-20 00:37:34 +03:00
@@ -1082,7 +1082,7 @@
 
     if (mysql_prepare_insert(thd, table_list, table_list->table,
                              fields, values, update_fields, update_values,
-                             duplic, &unused_conds, FALSE))
+                             duplic, &unused_conds, FALSE, FALSE, FALSE))
       goto error;
 
     value_count= values->elements;

--- 1.58/sql/sql_help.cc	2007-03-17 02:13:18 +03:00
+++ 1.59/sql/sql_help.cc	2007-03-20 00:37:33 +03:00
@@ -654,8 +654,9 @@
   tables[3].lock_type= TL_READ;
   tables[0].db= tables[1].db= tables[2].db= tables[3].db= (char*) "mysql";
 
-  if (open_and_lock_tables(thd, tables))
-    goto error;
+  Open_tables_state open_tables_state_backup;
+  if (open_system_tables_for_read(thd, tables, &open_tables_state_backup))
+    goto error2;
 
   /*
     Init tables and fields to be usable from items
@@ -780,8 +781,13 @@
   }
   send_eof(thd);
 
+  close_system_tables(thd, &open_tables_state_backup);
   DBUG_RETURN(FALSE);
+
 error:
+  close_system_tables(thd, &open_tables_state_backup);
+
+error2:
   DBUG_RETURN(TRUE);
 }
 
Thread
bk commit into 5.1 tree (kostja:1.2505)konstantin19 Mar