List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:July 28 2006 6:03pm
Subject:bk commit into 5.0 tree (anozdrin:1.2244) BUG#16899
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of alik. When alik 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, 2006-07-28 20:03:09+04:00, anozdrin@alik. +36 -0
  Fix for BUG#16899: Possible buffer overflow in handling of DEFINER-clause
  
  User name (host name) has limit on length. The server code relies on these
  limits when storing the names. The problem was that sometimes these limits were
  not checked properly, so that could lead to buffer overflow.
  
  The fix is to:
  
    1. Introduce User_name and Host_name classes, which incapsulate user name and
       host name respectively. These classes check for limits. If the limit is
       exceeded, the string should be trimmed and warning should be thrown.
  
    2. Transform LEX_USER to class Lex_user, which contains User_name and
       Host_name instances.
  
    3. Change trigger-handling code so that statement query is produced once for
       replication log and trigger file.

  BitKeeper/etc/collapsed@stripped, 2006-07-28 17:35:18+04:00, anozdrin@alik. +1 -0
    BitKeeper file /mnt/raid/alik/MySQL/devel/5.0-rt-bug16899/BitKeeper/etc/collapsed

  BitKeeper/etc/collapsed@stripped, 2006-07-28 17:35:18+04:00, anozdrin@alik. +0 -0

  client/mysqldump.c@stripped, 2006-07-28 20:03:06+04:00, anozdrin@alik. +44 -18
    Updated parse_user().

  include/m_string.h@stripped, 2006-07-28 20:03:06+04:00, anozdrin@alik. +18 -0
    Moved LEX_STRING out of server directory.

  include/my_user.h@stripped, 2006-07-28 20:03:06+04:00, anozdrin@alik. +8 -3
    Updated parse_user().

  mysql-test/r/sp.result@stripped, 2006-07-28 20:03:06+04:00, anozdrin@alik. +23 -0
    Updated result file.

  mysql-test/r/trigger.result@stripped, 2006-07-28 20:03:06+04:00, anozdrin@alik. +21 -0
    Updated result file.

  mysql-test/r/view.result@stripped, 2006-07-28 20:03:06+04:00, anozdrin@alik. +27 -0
    Updated result file.

  mysql-test/t/sp.test@stripped, 2006-07-28 20:03:06+04:00, anozdrin@alik. +36 -0
    Added test for BUG#16899.

  mysql-test/t/trigger.test@stripped, 2006-07-28 20:03:06+04:00, anozdrin@alik. +36 -0
    Updated result file.

  mysql-test/t/view.test@stripped, 2006-07-28 20:03:06+04:00, anozdrin@alik. +32 -0
    Updated result file.

  sql-common/my_user.c@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +38 -20
    parse_user() impl.

  sql/mysql_priv.h@stripped, 2006-07-28 20:03:06+04:00, anozdrin@alik. +4 -4
    Added convenient get_field() function.

  sql/set_var.cc@stripped, 2006-07-28 20:03:06+04:00, anozdrin@alik. +28 -9
    Updated set_var_password() to work with modified LEX_USER.

  sql/set_var.h@stripped, 2006-07-28 20:03:06+04:00, anozdrin@alik. +8 -5
    Updated set_var_password() to work with modified LEX_USER.
    ---
    Updated set_var_password() to work with modified LEX_USER.
    ---
    Updated set_var_password() to work with modified LEX_USER.

  sql/share/errmsg.txt@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +4 -0
    Aded new error messages.

  sql/sp.cc@stripped, 2006-07-28 20:03:06+04:00, anozdrin@alik. +37 -23
    Updated.

  sql/sp_head.cc@stripped, 2006-07-28 20:03:06+04:00, anozdrin@alik. +17 -5
    Use new parse_user().

  sql/sp_head.h@stripped, 2006-07-28 20:03:06+04:00, anozdrin@alik. +1 -1
    Use LEX_STRING.
    ---
    Use LEX_STRING.
    ---
    Use LEX_STRING.

  sql/spatial.cc@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +4 -1
    Get rid of LEX_STRING_WITH_INIT.

  sql/spatial.h@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +1 -1
    Get rid of LEX_STRING_WITH_INIT.

  sql/sql_acl.cc@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +276 -163
    Reflect LEX_USER changes.
    ---
    Reflect LEX_USER changes.
    ---
    Reflect LEX_USER changes.

  sql/sql_acl.h@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +8 -8
    LEX_USER -> Lex_user

  sql/sql_class.cc@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +25 -0
    Provide server-wide callbacks for parse_user().

  sql/sql_class.h@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +9 -0
    Provide server-wide callbacks for parse_user().
    ---
    Provide server-wide callbacks for parse_user().
    ---
    Provide server-wide callbacks for parse_user().

  sql/sql_lex.h@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +3 -3
    LEX_USER -> Lex_user

  sql/sql_parse.cc@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +52 -76
    1. Reflect LEX_USER changes.
    2. Eleminate create_definer().

  sql/sql_show.cc@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +13 -6
    Reflect LEX_USER changes.

  sql/sql_string.h@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +0 -2
    Get rid of STRING_WITH_LEN.

  sql/sql_trigger.cc@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +72 -71
    1. Reflect LEX_USER changes.
    2. Changed trigger-handling code so that there will be the one
       place for generate statement string for replication log
       and for trigger file.

  sql/sql_trigger.h@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +2 -4
    Changed trigger-handling code so that there will be the one
    place for generate statement string for replication log
    and for trigger file.

  sql/sql_view.cc@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +16 -16
    Reflect LEX_USER changes.

  sql/sql_yacc.yy@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +43 -31
    Reflect LEX_USER changes.

  sql/structs.cc@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +107 -0
    User_name, Host_name, LEX_USER impl.

  sql/structs.cc@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +0 -0

  sql/structs.h@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +0 -21
    LEX_USER changed.

  sql/table.cc@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +145 -19
    Reflect LEX_USER changes.

  sql/table.h@stripped, 2006-07-28 20:03:07+04:00, anozdrin@alik. +104 -1
    Reflect LEX_USER changes.

# 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:	anozdrin
# Host:	alik.
# Root:	/mnt/raid/alik/MySQL/devel/5.0-rt-bug16899

--- 1.232/client/mysqldump.c	2006-07-28 20:03:15 +04:00
+++ 1.233/client/mysqldump.c	2006-07-28 20:03:15 +04:00
@@ -1893,6 +1893,22 @@ continue_xml:
 } /* get_table_structure */
 
 
+static void on_user_name_truncated()
+{
+  fprintf(stderr,
+          "Warning: the user name has been truncated to %d symbols\n",
+          (int) USERNAME_LENGTH);
+}
+
+
+static void on_host_name_truncated()
+{
+  fprintf(stderr,
+          "Warning: the host name has been truncated to %d symbols\n",
+          (int) HOSTNAME_LENGTH);
+}
+
+
 /*
 
   dump_triggers_for_table
@@ -1949,20 +1965,25 @@ DELIMITER ;;\n");
         we should check if we have this column before accessing it.
       */
 
-      uint       user_name_len;
-      char       user_name_str[USERNAME_LENGTH + 1];
+      LEX_STRING user_id= { row[7], strlen(row[7]) };
+
+      char       user_name_holder[USERNAME_LENGTH + 1];
+      LEX_STRING user_name= { user_name_holder, USERNAME_LENGTH };
+
+      char       host_name_holder[HOSTNAME_LENGTH + 1];
+      LEX_STRING host_name= { host_name_holder, HOSTNAME_LENGTH };
+
       char       quoted_user_name_str[USERNAME_LENGTH * 2 + 3];
-      uint       host_name_len;
-      char       host_name_str[HOSTNAME_LENGTH + 1];
       char       quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3];
 
-      parse_user(row[7], strlen(row[7]), user_name_str, &user_name_len,
-                 host_name_str, &host_name_len);
+      parse_user(&user_id, &user_name, &host_name,
+                 on_user_name_truncated,
+                 on_host_name_truncated);
 
       fprintf(sql_file,
               "/*!50017 DEFINER=%s@%s */ ",
-              quote_name(user_name_str, quoted_user_name_str, FALSE),
-              quote_name(host_name_str, quoted_host_name_str, FALSE));
+              quote_name(user_name.str, quoted_user_name_str, FALSE),
+              quote_name(host_name.str, quoted_host_name_str, FALSE));
     }
 
     fprintf(sql_file,
@@ -3465,29 +3486,34 @@ static my_bool get_view_structure(char *
       Surround it with !50013 comments
     */
     {
-      uint       user_name_len;
-      char       user_name_str[USERNAME_LENGTH + 1];
+      LEX_STRING user_id= { row[1], lengths[1] };
+
+      char       user_name_holder[USERNAME_LENGTH + 1];
+      LEX_STRING user_name= { user_name_holder, USERNAME_LENGTH };
+
+      char       host_name_holder[HOSTNAME_LENGTH + 1];
+      LEX_STRING host_name= { host_name_holder, HOSTNAME_LENGTH };
+
       char       quoted_user_name_str[USERNAME_LENGTH * 2 + 3];
-      uint       host_name_len;
-      char       host_name_str[HOSTNAME_LENGTH + 1];
       char       quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3];
 
-      parse_user(row[1], lengths[1], user_name_str, &user_name_len,
-                 host_name_str, &host_name_len);
+      parse_user(&user_id, &user_name, &host_name,
+                 on_user_name_truncated,
+                 on_host_name_truncated);
 
       ptr= search_buf;
       search_len=
         (ulong)(strxmov(ptr, "DEFINER=",
-                        quote_name(user_name_str, quoted_user_name_str, FALSE),
+                        quote_name(user_name.str, quoted_user_name_str, FALSE),
                         "@",
-                        quote_name(host_name_str, quoted_host_name_str, FALSE),
+                        quote_name(host_name.str, quoted_host_name_str, FALSE),
                         " SQL SECURITY ", row[2], NullS) - ptr);
       ptr= replace_buf;
       replace_len=
         (ulong)(strxmov(ptr, "*/\n/*!50013 DEFINER=",
-                        quote_name(user_name_str, quoted_user_name_str, FALSE),
+                        quote_name(user_name.str, quoted_user_name_str, FALSE),
                         "@",
-                        quote_name(host_name_str, quoted_host_name_str, FALSE),
+                        quote_name(host_name.str, quoted_host_name_str, FALSE),
                         " SQL SECURITY ", row[2],
                         " */\n/*!50001", NullS) - ptr);
       replace(&ds_view, search_buf, search_len, replace_buf, replace_len);

--- 1.37/include/m_string.h	2006-07-28 20:03:15 +04:00
+++ 1.38/include/m_string.h	2006-07-28 20:03:15 +04:00
@@ -259,4 +259,22 @@ extern int my_snprintf(char* to, size_t 
 #if defined(__cplusplus) && !defined(OS2)
 }
 #endif
+
+/*
+  LEX_STRING -- a pair of a C-string and its length.
+
+  NOTE: this exactly form of declaration is required for some C-compilers
+  (for one, Sun C 5.7 2005/01/07). Unfortunately with such declaration
+  LEX_STRING can not be forward declared.
+*/
+
+typedef struct
+{
+  char *str;
+  uint length;
+} LEX_STRING;
+
+#define STRING_WITH_LEN(X) (X), ((uint) (sizeof(X) - 1))
+#define C_STRING_WITH_LEN(X) ((char *) (X)), ((uint) (sizeof(X) - 1))
+
 #endif

--- 1.399/sql/mysql_priv.h	2006-07-28 20:03:15 +04:00
+++ 1.400/sql/mysql_priv.h	2006-07-28 20:03:15 +04:00
@@ -551,10 +551,9 @@ bool create_table_precheck(THD *thd, TAB
 int append_query_string(CHARSET_INFO *csinfo,
                         String const *from, String *to);
 
-void get_default_definer(THD *thd, LEX_USER *definer);
-LEX_USER *create_default_definer(THD *thd);
-LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name);
-LEX_USER *get_current_user(THD *thd, LEX_USER *user);
+void get_default_definer(THD *thd, Lex_user *definer);
+Lex_user *create_default_definer(THD *thd);
+Lex_user *get_current_user(THD *thd, Lex_user *user);
 
 enum enum_mysql_completiontype {
   ROLLBACK_RELEASE=-2, ROLLBACK=1,  ROLLBACK_AND_CHAIN=7,
@@ -1465,6 +1464,7 @@ int rename_file_ext(const char * from,co
 bool check_db_name(char *db);
 bool check_column_name(const char *name);
 bool check_table_name(const char *name, uint length);
+bool get_field(MEM_ROOT *mem, Field *field, LEX_STRING *value);
 char *get_field(MEM_ROOT *mem, Field *field);
 bool get_field(MEM_ROOT *mem, Field *field, class String *res);
 int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr);

--- 1.198/sql/sql_acl.cc	2006-07-28 20:03:15 +04:00
+++ 1.199/sql/sql_acl.cc	2006-07-28 20:03:15 +04:00
@@ -1737,7 +1737,7 @@ static bool test_if_create_new_users(THD
   Handle GRANT commands
 ****************************************************************************/
 
-static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
+static int replace_user_table(THD *thd, TABLE *table, const Lex_user &combo,
 			      ulong rights, bool revoke_grant,
 			      bool can_create_user, bool no_auto_create)
 {
@@ -1764,8 +1764,12 @@ static int replace_user_table(THD *thd, 
     password=combo.password.str;
   }
 
-  table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
-  table->field[1]->store(combo.user.str,combo.user.length, system_charset_info);
+  table->field[0]->store(combo.host_name.get_c_str(),
+                         combo.host_name.get_length(),
+                         system_charset_info);
+  table->field[1]->store(combo.user_name.get_c_str(),
+                         combo.user_name.get_length(),
+                         system_charset_info);
   key_copy(user_key, table->record[0], table->key_info,
            table->key_info->key_length);
 
@@ -1777,7 +1781,9 @@ static int replace_user_table(THD *thd, 
     /* what == 'N' means revoke */
     if (what == 'N')
     {
-      my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str);
+      my_error(ER_NONEXISTING_GRANT, MYF(0),
+               combo.user_name.get_c_str(),
+               combo.host_name.get_c_str());
       goto end;
     }
     /*
@@ -1795,20 +1801,25 @@ static int replace_user_table(THD *thd, 
     */
     else if (!password_len && no_auto_create)
     {
-      my_error(ER_PASSWORD_NO_MATCH, MYF(0), combo.user.str, combo.host.str);
+      my_error(ER_PASSWORD_NO_MATCH, MYF(0),
+               combo.user_name.get_c_str(),
+               combo.host_name.get_c_str());
       goto end;
     }
     else if (!can_create_user)
     {
       my_error(ER_CANT_CREATE_USER_WITH_GRANT, MYF(0),
-               thd->security_ctx->user, thd->security_ctx->host_or_ip);
+               thd->security_ctx->user,
+               thd->security_ctx->host_or_ip);
       goto end;
     }
     old_row_exists = 0;
     restore_record(table,s->default_values);
-    table->field[0]->store(combo.host.str,combo.host.length,
+    table->field[0]->store(combo.host_name.get_c_str(),
+                           combo.host_name.get_length(),
                            system_charset_info);
-    table->field[1]->store(combo.user.str,combo.user.length,
+    table->field[1]->store(combo.user_name.get_c_str(),
+                           combo.user_name.get_length(),
                            system_charset_info);
     table->field[2]->store(password, password_len,
                            system_charset_info);
@@ -1931,7 +1942,8 @@ end:
   {
     acl_cache->clear(1);			// Clear privilege cache
     if (old_row_exists)
-      acl_update_user(combo.user.str, combo.host.str,
+      acl_update_user(combo.user_name.get_c_str(),
+                      combo.host_name.get_c_str(),
                       combo.password.str, password_len,
 		      lex->ssl_type,
 		      lex->ssl_cipher,
@@ -1940,7 +1952,9 @@ end:
 		      &lex->mqh,
 		      rights);
     else
-      acl_insert_user(combo.user.str, combo.host.str, password, password_len,
+      acl_insert_user(combo.user_name.get_c_str(),
+                      combo.host_name.get_c_str(),
+                      password, password_len,
 		      lex->ssl_type,
 		      lex->ssl_cipher,
 		      lex->x509_issuer,
@@ -1957,7 +1971,7 @@ end:
 */
 
 static int replace_db_table(TABLE *table, const char *db,
-			    const LEX_USER &combo,
+			    const Lex_user &combo,
 			    ulong rights, bool revoke_grant)
 {
   uint i;
@@ -1975,15 +1989,20 @@ static int replace_db_table(TABLE *table
   }
 
   /* Check if there is such a user in user table in memory? */
-  if (!find_acl_user(combo.host.str,combo.user.str, FALSE))
+  if (!find_acl_user(combo.host_name.get_c_str(),
+                     combo.user_name.get_c_str(), FALSE))
   {
     my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0));
     DBUG_RETURN(-1);
   }
 
-  table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+  table->field[0]->store(combo.host_name.get_c_str(),
+                         combo.host_name.get_length(),
+                         system_charset_info);
   table->field[1]->store(db,(uint) strlen(db), system_charset_info);
-  table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
+  table->field[2]->store(combo.user_name.get_c_str(),
+                         combo.user_name.get_length(),
+                         system_charset_info);
   key_copy(user_key, table->record[0], table->key_info,
            table->key_info->key_length);
 
@@ -1994,14 +2013,20 @@ static int replace_db_table(TABLE *table
   {
     if (what == 'N')
     { // no row, no revoke
-      my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str);
+      my_error(ER_NONEXISTING_GRANT, MYF(0),
+               combo.user_name.get_c_str(),
+               combo.host_name.get_c_str());
       goto abort;
     }
     old_row_exists = 0;
     restore_record(table, s->default_values);
-    table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+    table->field[0]->store(combo.host_name.get_c_str(),
+                           combo.host_name.get_length(),
+                           system_charset_info);
     table->field[1]->store(db,(uint) strlen(db), system_charset_info);
-    table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
+    table->field[2]->store(combo.user_name.get_c_str(),
+                           combo.user_name.get_length(),
+                           system_charset_info);
   }
   else
   {
@@ -2041,10 +2066,13 @@ static int replace_db_table(TABLE *table
 
   acl_cache->clear(1);				// Clear privilege cache
   if (old_row_exists)
-    acl_update_db(combo.user.str,combo.host.str,db,rights);
-  else
-  if (rights)
-    acl_insert_db(combo.user.str,combo.host.str,db,rights);
+    acl_update_db(combo.user_name.get_c_str(),
+                  combo.host_name.get_c_str(),
+                  db, rights);
+  else if (rights)
+    acl_insert_db(combo.user_name.get_c_str(),
+                  combo.host_name.get_c_str(),
+                  db, rights);
   DBUG_RETURN(0);
 
   /* This could only happen if the grant tables got corrupted */
@@ -2320,7 +2348,7 @@ column_hash_search(GRANT_TABLE *t, const
 
 
 static int replace_column_table(GRANT_TABLE *g_t,
-				TABLE *table, const LEX_USER &combo,
+				TABLE *table, const Lex_user &combo,
 				List <LEX_COLUMN> &columns,
 				const char *db, const char *table_name,
 				ulong rights, bool revoke_grant)
@@ -2331,11 +2359,13 @@ static int replace_column_table(GRANT_TA
   KEY_PART_INFO *key_part= table->key_info->key_part;
   DBUG_ENTER("replace_column_table");
 
-  table->field[0]->store(combo.host.str,combo.host.length,
+  table->field[0]->store(combo.host_name.get_c_str(),
+                         combo.host_name.get_length(),
                          system_charset_info);
   table->field[1]->store(db,(uint) strlen(db),
                          system_charset_info);
-  table->field[2]->store(combo.user.str,combo.user.length,
+  table->field[2]->store(combo.user_name.get_c_str(),
+                         combo.user_name.get_length(),
                          system_charset_info);
   table->field[3]->store(table_name,(uint) strlen(table_name),
                          system_charset_info);
@@ -2374,7 +2404,8 @@ static int replace_column_table(GRANT_TA
       if (revoke_grant)
       {
 	my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
-                 combo.user.str, combo.host.str,
+                 combo.user_name.get_c_str(),
+                 combo.host_name.get_c_str(),
                  table_name);                   /* purecov: inspected */
 	result= -1;                             /* purecov: inspected */
 	continue;                               /* purecov: inspected */
@@ -2508,7 +2539,7 @@ end:
 
 
 static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
-			       TABLE *table, const LEX_USER &combo,
+			       TABLE *table, const Lex_user &combo,
 			       const char *db, const char *table_name,
 			       ulong rights, ulong col_rights,
 			       bool revoke_grant)
@@ -2527,7 +2558,8 @@ static int replace_table_table(THD *thd,
     The following should always succeed as new users are created before
     this function is called!
   */
-  if (!find_acl_user(combo.host.str,combo.user.str, FALSE))
+  if (!find_acl_user(combo.host_name.get_c_str(),
+                     combo.user_name.get_c_str(), FALSE))
   {
     my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH),
                MYF(0));	/* purecov: deadcode */
@@ -2535,9 +2567,13 @@ static int replace_table_table(THD *thd,
   }
 
   restore_record(table, s->default_values);     // Get empty record
-  table->field[0]->store(combo.host.str,combo.host.length, system_charset_info);
+  table->field[0]->store(combo.host_name.get_c_str(),
+                         combo.host_name.get_length(),
+                         system_charset_info);
   table->field[1]->store(db,(uint) strlen(db), system_charset_info);
-  table->field[2]->store(combo.user.str,combo.user.length, system_charset_info);
+  table->field[2]->store(combo.user_name.get_c_str(),
+                         combo.user_name.get_length(),
+                         system_charset_info);
   table->field[3]->store(table_name,(uint) strlen(table_name),
system_charset_info);
   store_record(table,record[1]);			// store at pos 1
   key_copy(user_key, table->record[0], table->key_info,
@@ -2556,7 +2592,8 @@ static int replace_table_table(THD *thd,
     if (revoke_grant)
     { // no row, no revoke
       my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
-               combo.user.str, combo.host.str,
+               combo.user_name.get_c_str(),
+               combo.host_name.get_c_str(),
                table_name);		        /* purecov: deadcode */
       DBUG_RETURN(-1);				/* purecov: deadcode */
     }
@@ -2627,7 +2664,7 @@ table_error:
 
 
 static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
-			      TABLE *table, const LEX_USER &combo,
+			      TABLE *table, const Lex_user &combo,
 			      const char *db, const char *routine_name,
 			      bool is_proc, ulong rights, bool revoke_grant)
 {
@@ -2650,16 +2687,20 @@ static int replace_routine_table(THD *th
     The following should always succeed as new users are created before
     this function is called!
   */
-  if (!find_acl_user(combo.host.str, combo.user.str, FALSE))
+  if (!find_acl_user(combo.host_name.get_c_str(),
+                     combo.user_name.get_c_str(),
+                     FALSE))
   {
     my_error(ER_PASSWORD_NO_MATCH,MYF(0));
     DBUG_RETURN(-1);
   }
 
   restore_record(table, s->default_values);		// Get empty record
-  table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
+  table->field[0]->store(combo.host_name.get_c_str(),
+                         combo.host_name.get_length(), &my_charset_latin1);
   table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
-  table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
+  table->field[2]->store(combo.user_name.get_c_str(),
+                         combo.user_name.get_length(), &my_charset_latin1);
   table->field[3]->store(routine_name,(uint) strlen(routine_name),
                          &my_charset_latin1);
   table->field[4]->store((longlong)(is_proc ? 
@@ -2679,7 +2720,9 @@ static int replace_routine_table(THD *th
     if (revoke_grant)
     { // no row, no revoke
       my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
-               combo.user.str, combo.host.str, routine_name);
+               combo.user_name.get_c_str(),
+               combo.host_name.get_c_str(),
+               routine_name);
       DBUG_RETURN(-1);
     }
     old_row_exists= 0;
@@ -2760,13 +2803,13 @@ table_error:
 */
 
 bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
-		      List <LEX_USER> &user_list,
+		      List <Lex_user> &user_list,
 		      List <LEX_COLUMN> &columns, ulong rights,
 		      bool revoke_grant)
 {
   ulong column_priv= 0;
-  List_iterator <LEX_USER> str_list (user_list);
-  LEX_USER *Str, *tmp_Str;
+  List_iterator <Lex_user> str_list (user_list);
+  Lex_user *Str, *tmp_Str;
   TABLE_LIST tables[3];
   bool create_new_users=0;
   char *db_name, *table_name;
@@ -2900,8 +2943,8 @@ bool mysql_table_grant(THD *thd, TABLE_L
       result= TRUE;
       continue;
     }  
-    if (Str->host.length > HOSTNAME_LENGTH ||
-	Str->user.length > USERNAME_LENGTH)
+    if (Str->host_name.get_length() > HOSTNAME_LENGTH ||
+	Str->user_name.get_length() > USERNAME_LENGTH)
     {
       my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
                  MYF(0));
@@ -2927,19 +2970,21 @@ bool mysql_table_grant(THD *thd, TABLE_L
 		table_list->table_name);
 
     /* Find/create cached table grant */
-    grant_table= table_hash_search(Str->host.str, NullS, db_name,
-				   Str->user.str, table_name, 1);
+    grant_table= table_hash_search(Str->host_name.get_c_str(), NullS, db_name,
+				   Str->user_name.get_c_str(), table_name, 1);
     if (!grant_table)
     {
       if (revoke_grant)
       {
 	my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
-                 Str->user.str, Str->host.str, table_list->table_name);
+                 Str->user_name.get_c_str(),
+                 Str->host_name.get_c_str(),
+                 table_list->table_name);
 	result= TRUE;
 	continue;
       }
-      grant_table = new GRANT_TABLE (Str->host.str, db_name,
-				     Str->user.str, table_name,
+      grant_table = new GRANT_TABLE (Str->host_name.get_c_str(), db_name,
+                                     Str->user_name.get_c_str(), table_name,
 				     rights,
 				     column_priv);
       if (!grant_table)				// end of memory
@@ -3031,11 +3076,11 @@ bool mysql_table_grant(THD *thd, TABLE_L
 */
 
 bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
-			 List <LEX_USER> &user_list, ulong rights,
+			 List <Lex_user> &user_list, ulong rights,
 			 bool revoke_grant, bool no_error)
 {
-  List_iterator <LEX_USER> str_list (user_list);
-  LEX_USER *Str, *tmp_Str;
+  List_iterator <Lex_user> str_list (user_list);
+  Lex_user *Str, *tmp_Str;
   TABLE_LIST tables[2];
   bool create_new_users=0, result=0;
   char *db_name, *table_name;
@@ -3112,8 +3157,8 @@ bool mysql_routine_grant(THD *thd, TABLE
       result= TRUE;
       continue;
     }  
-    if (Str->host.length > HOSTNAME_LENGTH ||
-	Str->user.length > USERNAME_LENGTH)
+    if (Str->host_name.get_length() > HOSTNAME_LENGTH ||
+	Str->user_name.get_length() > USERNAME_LENGTH)
     {
       if (!no_error)
 	my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
@@ -3135,20 +3180,23 @@ bool mysql_routine_grant(THD *thd, TABLE
     db_name= table_list->db;
     table_name= table_list->table_name;
 
-    grant_name= routine_hash_search(Str->host.str, NullS, db_name,
-                                    Str->user.str, table_name, is_proc, 1);
+    grant_name= routine_hash_search(Str->host_name.get_c_str(), NullS,
+                                    db_name, Str->user_name.get_c_str(),
+                                    table_name, is_proc, 1);
     if (!grant_name)
     {
       if (revoke_grant)
       {
         if (!no_error)
           my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
-		   Str->user.str, Str->host.str, table_name);
+                   Str->user_name.get_c_str(),
+                   Str->host_name.get_c_str(),
+                   table_name);
 	result= TRUE;
 	continue;
       }
-      grant_name= new GRANT_NAME(Str->host.str, db_name,
-				 Str->user.str, table_name,
+      grant_name= new GRANT_NAME(Str->host_name.get_c_str(), db_name,
+                                 Str->user_name.get_c_str(), table_name,
 				 rights);
       if (!grant_name)
       {
@@ -3176,11 +3224,11 @@ bool mysql_routine_grant(THD *thd, TABLE
 }
 
 
-bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
+bool mysql_grant(THD *thd, const char *db, List <Lex_user> &list,
                  ulong rights, bool revoke_grant)
 {
-  List_iterator <LEX_USER> str_list (list);
-  LEX_USER *Str, *tmp_Str;
+  List_iterator <Lex_user> str_list (list);
+  Lex_user *Str, *tmp_Str;
   char tmp_db[NAME_LEN+1];
   bool create_new_users=0;
   TABLE_LIST tables[2];
@@ -3246,8 +3294,8 @@ bool mysql_grant(THD *thd, const char *d
       result= TRUE;
       continue;
     }  
-    if (Str->host.length > HOSTNAME_LENGTH ||
-	Str->user.length > USERNAME_LENGTH)
+    if (Str->host_name.get_length() > HOSTNAME_LENGTH ||
+	Str->user_name.get_length() > USERNAME_LENGTH)
     {
       my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
                  MYF(0));
@@ -4114,7 +4162,7 @@ static uint command_lengths[]=
 };
 
 
-static int show_routine_grants(THD *thd, LEX_USER *lex_user, HASH *hash,
+static int show_routine_grants(THD *thd, Lex_user *lex_user, HASH *hash,
                                const char *type, int typelen,
                                char *buff, int buffsize);
 
@@ -4126,7 +4174,7 @@ static int show_routine_grants(THD *thd,
    Send to client grant-like strings depicting user@host privileges
 */
 
-bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
+bool mysql_show_grants(THD *thd,Lex_user *lex_user)
 {
   ulong want_access;
   uint counter,index;
@@ -4144,8 +4192,8 @@ bool mysql_show_grants(THD *thd,LEX_USER
     DBUG_RETURN(TRUE);
   }
 
-  if (lex_user->host.length > HOSTNAME_LENGTH ||
-      lex_user->user.length > USERNAME_LENGTH)
+  if (lex_user->host_name.get_length() > HOSTNAME_LENGTH ||
+      lex_user->user_name.get_length() > USERNAME_LENGTH)
   {
     my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
                MYF(0));
@@ -4155,14 +4203,16 @@ bool mysql_show_grants(THD *thd,LEX_USER
   rw_rdlock(&LOCK_grant);
   VOID(pthread_mutex_lock(&acl_cache->lock));
 
-  acl_user= find_acl_user(lex_user->host.str, lex_user->user.str, TRUE);
+  acl_user= find_acl_user(lex_user->host_name.get_c_str(),
+                          lex_user->user_name.get_c_str(), TRUE);
   if (!acl_user)
   {
     VOID(pthread_mutex_unlock(&acl_cache->lock));
     rw_unlock(&LOCK_grant);
 
     my_error(ER_NONEXISTING_GRANT, MYF(0),
-             lex_user->user.str, lex_user->host.str);
+             lex_user->user_name.get_c_str(),
+             lex_user->host_name.get_c_str());
     DBUG_RETURN(TRUE);
   }
 
@@ -4170,8 +4220,8 @@ bool mysql_show_grants(THD *thd,LEX_USER
   List<Item> field_list;
   field->name=buff;
   field->max_length=1024;
-  strxmov(buff,"Grants for ",lex_user->user.str,"@",
-	  lex_user->host.str,NullS);
+  strxmov(buff, "Grants for ", lex_user->user_name.get_c_str(), "@",
+          lex_user->host_name.get_c_str(), NullS);
   field_list.push_back(field);
   if (protocol->send_fields(&field_list,
                             Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
@@ -4209,10 +4259,12 @@ bool mysql_show_grants(THD *thd,LEX_USER
       }
     }
     global.append (STRING_WITH_LEN(" ON *.* TO '"));
-    global.append(lex_user->user.str, lex_user->user.length,
+    global.append(lex_user->user_name.get_c_str(),
+                  lex_user->user_name.get_length(),
 		  system_charset_info);
     global.append (STRING_WITH_LEN("'@'"));
-    global.append(lex_user->host.str,lex_user->host.length,
+    global.append(lex_user->host_name.get_c_str(),
+                  lex_user->host_name.get_length(),
 		  system_charset_info);
     global.append ('\'');
     if (acl_user->salt_len)
@@ -4299,8 +4351,9 @@ bool mysql_show_grants(THD *thd,LEX_USER
     if (!(host=acl_db->host.hostname))
       host= "";
 
-    if (!strcmp(lex_user->user.str,user) &&
-	!my_strcasecmp(system_charset_info, lex_user->host.str, host))
+    if (!strcmp(lex_user->user_name.get_c_str(), user) &&
+        !my_strcasecmp(system_charset_info, lex_user->host_name.get_c_str(),
+                       host))
     {
       want_access=acl_db->access;
       if (want_access)
@@ -4331,10 +4384,12 @@ bool mysql_show_grants(THD *thd,LEX_USER
 	db.append (STRING_WITH_LEN(" ON "));
 	append_identifier(thd, &db, acl_db->db, strlen(acl_db->db));
 	db.append (STRING_WITH_LEN(".* TO '"));
-	db.append(lex_user->user.str, lex_user->user.length,
+        db.append(lex_user->user_name.get_c_str(),
+                  lex_user->user_name.get_length(),
 		  system_charset_info);
 	db.append (STRING_WITH_LEN("'@'"));
-	db.append(lex_user->host.str, lex_user->host.length,
+        db.append(lex_user->host_name.get_c_str(),
+                  lex_user->host_name.get_length(),
                   system_charset_info);
 	db.append ('\'');
 	if (want_access & GRANT_ACL)
@@ -4362,8 +4417,10 @@ bool mysql_show_grants(THD *thd,LEX_USER
     if (!(host= grant_table->host.hostname))
       host= "";
 
-    if (!strcmp(lex_user->user.str,user) &&
-	!my_strcasecmp(system_charset_info, lex_user->host.str, host))
+    if (!strcmp(lex_user->user_name.get_c_str(), user) &&
+        !my_strcasecmp(system_charset_info,
+                       lex_user->host_name.get_c_str(),
+                       host))
     {
       ulong table_access= grant_table->privs;
       if ((table_access | grant_table->cols) != 0)
@@ -4439,10 +4496,12 @@ bool mysql_show_grants(THD *thd,LEX_USER
 	append_identifier(thd, &global, grant_table->tname,
 			  strlen(grant_table->tname));
 	global.append(STRING_WITH_LEN(" TO '"));
-	global.append(lex_user->user.str, lex_user->user.length,
+        global.append(lex_user->user_name.get_c_str(),
+                      lex_user->user_name.get_length(),
 		      system_charset_info);
 	global.append(STRING_WITH_LEN("'@'"));
-	global.append(lex_user->host.str,lex_user->host.length,
+	global.append(lex_user->host_name.get_c_str(),
+                      lex_user->host_name.get_length(),
 		      system_charset_info);
 	global.append('\'');
 	if (table_access & GRANT_ACL)
@@ -4480,7 +4539,7 @@ end:
   DBUG_RETURN(error);
 }
 
-static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash,
+static int show_routine_grants(THD* thd, Lex_user *lex_user, HASH *hash,
                                const char *type, int typelen,
                                char *buff, int buffsize)
 {
@@ -4498,8 +4557,10 @@ static int show_routine_grants(THD* thd,
     if (!(host= grant_proc->host.hostname))
       host= "";
 
-    if (!strcmp(lex_user->user.str,user) &&
-	!my_strcasecmp(system_charset_info, lex_user->host.str, host))
+    if (!strcmp(lex_user->user_name.get_c_str(), user) &&
+        !my_strcasecmp(system_charset_info,
+                       lex_user->host_name.get_c_str(),
+                       host))
     {
       ulong proc_access= grant_proc->privs;
       if (proc_access != 0)
@@ -4538,10 +4599,12 @@ static int show_routine_grants(THD* thd,
 	append_identifier(thd, &global, grant_proc->tname,
 			  strlen(grant_proc->tname));
 	global.append(STRING_WITH_LEN(" TO '"));
-	global.append(lex_user->user.str, lex_user->user.length,
+        global.append(lex_user->user_name.get_c_str(),
+                      lex_user->user_name.get_length(),
 		      system_charset_info);
 	global.append(STRING_WITH_LEN("'@'"));
-	global.append(lex_user->host.str,lex_user->host.length,
+	global.append(lex_user->host_name.get_c_str(),
+                      lex_user->host_name.get_length(),
 		      system_charset_info);
 	global.append('\'');
 	if (proc_access & GRANT_ACL)
@@ -4700,7 +4763,7 @@ int open_grant_tables(THD *thd, TABLE_LI
 */
 
 static int modify_grant_table(TABLE *table, Field *host_field,
-                              Field *user_field, LEX_USER *user_to)
+                              Field *user_field, Lex_user *user_to)
 {
   int error;
   DBUG_ENTER("modify_grant_table");
@@ -4709,9 +4772,11 @@ static int modify_grant_table(TABLE *tab
   {
     /* rename */
     store_record(table, record[1]);
-    host_field->store(user_to->host.str, user_to->host.length,
+    host_field->store(user_to->host_name.get_c_str(),
+                      user_to->host_name.get_length(),
                       system_charset_info);
-    user_field->store(user_to->user.str, user_to->user.length,
+    user_field->store(user_to->user_name.get_c_str(),
+                      user_to->user_name.get_length(),
                       system_charset_info);
     if ((error= table->file->update_row(table->record[1], table->record[0])))
       table->file->print_error(error, MYF(0));
@@ -4760,15 +4825,15 @@ static int modify_grant_table(TABLE *tab
 */
 
 static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
-                              LEX_USER *user_from, LEX_USER *user_to)
+                              Lex_user *user_from, Lex_user *user_to)
 {
   int result= 0;
   int error;
   TABLE *table= tables[table_no].table;
   Field *host_field= table->field[0];
   Field *user_field= table->field[table_no ? 2 : 1];
-  char *host_str= user_from->host.str;
-  char *user_str= user_from->user.str;
+  char *host_str= user_from->host_name.get_c_str();
+  char *user_str= user_from->user_name.get_c_str();
   const char *host;
   const char *user;
   byte user_key[MAX_KEY_LENGTH];
@@ -4788,8 +4853,10 @@ static int handle_grant_table(TABLE_LIST
     */
     DBUG_PRINT("info",("read table: '%s'  search: '%s'@'%s'",
                        table->s->table_name, user_str, host_str));
-    host_field->store(host_str, user_from->host.length, system_charset_info);
-    user_field->store(user_str, user_from->user.length, system_charset_info);
+    host_field->store(host_str, user_from->host_name.get_length(),
+                      system_charset_info);
+    user_field->store(user_str, user_from->user_name.get_length(),
+                      system_charset_info);
 
     key_prefix_length= (table->key_info->key_part[0].store_length +
                         table->key_info->key_part[1].store_length);
@@ -4904,7 +4971,7 @@ static int handle_grant_table(TABLE_LIST
 */
 
 static int handle_grant_struct(uint struct_no, bool drop,
-                               LEX_USER *user_from, LEX_USER *user_to)
+                               Lex_user *user_from, Lex_user *user_to)
 {
   int result= 0;
   uint idx;
@@ -4916,7 +4983,8 @@ static int handle_grant_struct(uint stru
   GRANT_NAME *grant_name;
   DBUG_ENTER("handle_grant_struct");
   DBUG_PRINT("info",("scan struct: %u  search: '%s'@'%s'",
-                     struct_no, user_from->user.str, user_from->host.str));
+                     struct_no, user_from->user_name.get_c_str(),
+                     user_from->host_name.get_c_str()));
 
   LINT_INIT(acl_user);
   LINT_INIT(acl_db);
@@ -4944,7 +5012,8 @@ static int handle_grant_struct(uint stru
 
 #ifdef EXTRA_DEBUG
     DBUG_PRINT("loop",("scan struct: %u  search    user: '%s'  host: '%s'",
-                       struct_no, user_from->user.str, user_from->host.str));
+                       struct_no, user_from->user_name.get_c_str(),
+                       user_from->host_name.get_c_str()));
 #endif
   /* Loop over all elements. */
   for (idx= 0; idx < elements; idx++)
@@ -4986,8 +5055,10 @@ static int handle_grant_struct(uint stru
     DBUG_PRINT("loop",("scan struct: %u  index: %u  user: '%s'  host: '%s'",
                        struct_no, idx, user, host));
 #endif
-    if (strcmp(user_from->user.str, user) ||
-        my_strcasecmp(system_charset_info, user_from->host.str, host))
+    if (strcmp(user_from->user_name.get_c_str(), user) ||
+        my_strcasecmp(system_charset_info,
+                      user_from->host_name.get_c_str(),
+                      host))
       continue;
 
     result= 1; /* At least one element found. */
@@ -5018,20 +5089,22 @@ static int handle_grant_struct(uint stru
     {
       switch ( struct_no ) {
       case 0:
-        acl_user->user= strdup_root(&mem, user_to->user.str);
-        acl_user->host.hostname= strdup_root(&mem, user_to->host.str);
+        acl_user->user= strdup_root(&mem, user_to->user_name.get_c_str());
+        acl_user->host.hostname= strdup_root(&mem,
+                                             user_to->host_name.get_c_str());
         break;
 
       case 1:
-        acl_db->user= strdup_root(&mem, user_to->user.str);
-        acl_db->host.hostname= strdup_root(&mem, user_to->host.str);
+        acl_db->user= strdup_root(&mem, user_to->user_name.get_c_str());
+        acl_db->host.hostname= strdup_root(&mem,
+                                           user_to->host_name.get_c_str());
         break;
 
       case 2:
       case 3:
-        grant_name->user= strdup_root(&mem, user_to->user.str);
+        grant_name->user= strdup_root(&mem, user_to->user_name.get_c_str());
         update_hostname(&grant_name->host,
-                        strdup_root(&mem, user_to->host.str));
+                        strdup_root(&mem, user_to->host_name.get_c_str()));
 	break;
       }
     }
@@ -5074,7 +5147,7 @@ static int handle_grant_struct(uint stru
 */
 
 static int handle_grant_data(TABLE_LIST *tables, bool drop,
-                             LEX_USER *user_from, LEX_USER *user_to)
+                             Lex_user *user_from, Lex_user *user_to)
 {
   int result= 0;
   int found;
@@ -5172,14 +5245,14 @@ static int handle_grant_data(TABLE_LIST 
 }
 
 
-static void append_user(String *str, LEX_USER *user)
+static void append_user(String *str, Lex_user *user)
 {
   if (str->length())
     str->append(',');
   str->append('\'');
-  str->append(user->user.str);
+  str->append(user->user_name.get_c_str());
   str->append(STRING_WITH_LEN("'@'"));
-  str->append(user->host.str);
+  str->append(user->host_name.get_c_str());
   str->append('\'');
 }
 
@@ -5197,13 +5270,13 @@ static void append_user(String *str, LEX
     TRUE        Error.
 */
 
-bool mysql_create_user(THD *thd, List <LEX_USER> &list)
+bool mysql_create_user(THD *thd, List <Lex_user> &list)
 {
   int result;
   String wrong_users;
   ulong sql_mode;
-  LEX_USER *user_name, *tmp_user_name;
-  List_iterator <LEX_USER> user_list(list);
+  Lex_user *user_name, *tmp_user_name;
+  List_iterator <Lex_user> user_list(list);
   TABLE_LIST tables[GRANT_TABLES];
   DBUG_ENTER("mysql_create_user");
 
@@ -5262,12 +5335,12 @@ bool mysql_create_user(THD *thd, List <L
     TRUE        Error.
 */
 
-bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
+bool mysql_drop_user(THD *thd, List <Lex_user> &list)
 {
   int result;
   String wrong_users;
-  LEX_USER *user_name, *tmp_user_name;
-  List_iterator <LEX_USER> user_list(list);
+  Lex_user *user_name, *tmp_user_name;
+  List_iterator <Lex_user> user_list(list);
   TABLE_LIST tables[GRANT_TABLES];
   DBUG_ENTER("mysql_drop_user");
 
@@ -5318,13 +5391,13 @@ bool mysql_drop_user(THD *thd, List <LEX
     TRUE        Error.
 */
 
-bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
+bool mysql_rename_user(THD *thd, List <Lex_user> &list)
 {
   int result;
   String wrong_users;
-  LEX_USER *user_from, *tmp_user_from;
-  LEX_USER *user_to, *tmp_user_to;
-  List_iterator <LEX_USER> user_list(list);
+  Lex_user *user_from, *tmp_user_from;
+  Lex_user *user_to, *tmp_user_to;
+  List_iterator <Lex_user> user_list(list);
   TABLE_LIST tables[GRANT_TABLES];
   DBUG_ENTER("mysql_rename_user");
 
@@ -5388,7 +5461,7 @@ bool mysql_rename_user(THD *thd, List <L
     < 0         Error. Error message not yet sent.
 */
 
-bool mysql_revoke_all(THD *thd,  List <LEX_USER> &list)
+bool mysql_revoke_all(THD *thd,  List <Lex_user> &list)
 {
   uint counter, revoked, is_proc;
   int result;
@@ -5402,19 +5475,21 @@ bool mysql_revoke_all(THD *thd,  List <L
   rw_wrlock(&LOCK_grant);
   VOID(pthread_mutex_lock(&acl_cache->lock));
 
-  LEX_USER *lex_user, *tmp_lex_user;
-  List_iterator <LEX_USER> user_list(list);
+  Lex_user *lex_user, *tmp_lex_user;
+  List_iterator <Lex_user> user_list(list);
   while ((tmp_lex_user= user_list++))
   {
     if (!(lex_user= get_current_user(thd, tmp_lex_user)))
     {
       result= -1;
       continue;
-    }  
-    if (!find_acl_user(lex_user->host.str, lex_user->user.str, TRUE))
+    }
+    if (!find_acl_user(lex_user->host_name.get_c_str(),
+                       lex_user->user_name.get_c_str(), TRUE))
     {
       sql_print_error("REVOKE ALL PRIVILEGES, GRANT: User '%s'@'%s' does not "
-                      "exists", lex_user->user.str, lex_user->host.str);
+                      "exists", lex_user->user_name.get_c_str(),
+                      lex_user->host_name.get_c_str());
       result= -1;
       continue;
     }
@@ -5444,8 +5519,10 @@ bool mysql_revoke_all(THD *thd,  List <L
 	if (!(host=acl_db->host.hostname))
 	  host= "";
 
-	if (!strcmp(lex_user->user.str,user) &&
-	    !my_strcasecmp(system_charset_info, lex_user->host.str, host))
+	if (!strcmp(lex_user->user_name.get_c_str(), user) &&
+            !my_strcasecmp(system_charset_info,
+                           lex_user->host_name.get_c_str(),
+                           host))
 	{
 	  if (!replace_db_table(tables[1].table, acl_db->db, *lex_user, ~(ulong)0, 1))
 	  {
@@ -5475,8 +5552,10 @@ bool mysql_revoke_all(THD *thd,  List <L
 	if (!(host=grant_table->host.hostname))
 	  host= "";
 
-	if (!strcmp(lex_user->user.str,user) &&
-	    !my_strcasecmp(system_charset_info, lex_user->host.str, host))
+	if (!strcmp(lex_user->user_name.get_c_str(), user) &&
+            !my_strcasecmp(system_charset_info,
+                           lex_user->host_name.get_c_str(),
+                           host))
 	{
 	  if (replace_table_table(thd,grant_table,tables[2].table,*lex_user,
 				  grant_table->db,
@@ -5521,8 +5600,10 @@ bool mysql_revoke_all(THD *thd,  List <L
 	if (!(host=grant_proc->host.hostname))
 	  host= "";
 
-	if (!strcmp(lex_user->user.str,user) &&
-	    !my_strcasecmp(system_charset_info, lex_user->host.str, host))
+	if (!strcmp(lex_user->user_name.get_c_str(), user) &&
+            !my_strcasecmp(system_charset_info,
+                           lex_user->host_name.get_c_str(),
+                           host))
 	{
 	  if (!replace_routine_table(thd,grant_proc,tables[4].table,*lex_user,
 				  grant_proc->db,
@@ -5589,13 +5670,24 @@ bool sp_revoke_privileges(THD *thd, cons
       if (!my_strcasecmp(system_charset_info, grant_proc->db, sp_db) &&
 	  !my_strcasecmp(system_charset_info, grant_proc->tname, sp_name))
       {
-        LEX_USER lex_user;
-	lex_user.user.str= grant_proc->user;
-	lex_user.user.length= strlen(grant_proc->user);
-	lex_user.host.str= grant_proc->host.hostname ?
-	  grant_proc->host.hostname : (char*)"";
-	lex_user.host.length= grant_proc->host.hostname ?
-	  strlen(grant_proc->host.hostname) : 0;
+        LEX_STRING user_name_str= { grant_proc->user,
+                                    strlen(grant_proc->user) };
+        LEX_STRING host_name_str;
+        Lex_user lex_user;
+
+        if (grant_proc->host.hostname)
+        {
+          host_name_str.str= grant_proc->host.hostname;
+          host_name_str.length= strlen(host_name_str.str);
+        }
+        else
+        {
+          host_name_str.str= (char *) "";
+          host_name_str.length= 1;
+        }
+
+        lex_user.set(thd, &user_name_str, &host_name_str, NULL);
+
 	if (!replace_routine_table(thd,grant_proc,tables[4].table,lex_user,
 				   grant_proc->db, grant_proc->tname,
                                    is_proc, ~(ulong)0, 1))
@@ -5638,35 +5730,62 @@ bool sp_grant_privileges(THD *thd, const
                          bool is_proc)
 {
   Security_context *sctx= thd->security_ctx;
-  LEX_USER *combo;
+  Lex_user *combo;
   TABLE_LIST tables[1];
-  List<LEX_USER> user_list;
+  List<Lex_user> user_list;
   bool result;
   ACL_USER *au;
   char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
   DBUG_ENTER("sp_grant_privileges");
 
-  if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
+  if (!(combo=(Lex_user*) thd->alloc(sizeof(Lex_user))))
     DBUG_RETURN(TRUE);
 
-  combo->user.str= sctx->user;
+  {
+    LEX_STRING user_name_str= { sctx->user, strlen(sctx->user) };
+    user_name_str.str= thd->strmake(user_name_str.str,
+                                    user_name_str.length);
+
+    combo->user_name.set(thd, &user_name_str);
+  }
 
-  VOID(pthread_mutex_lock(&acl_cache->lock));
+  {
+    const char *user_name= combo->user_name.get_c_str();
+    const char *host_name= NULL;
+    const char *host_name_variants[]=
+    {
+      sctx->host_or_ip,
+      sctx->host,
+      sctx->ip,
+      "%",
+      NULL
+    };
 
-  if ((au=
find_acl_user(combo->host.str=(char*)sctx->host_or_ip,combo->user.str,FALSE)))
-    goto found_acl;
-  if ((au= find_acl_user(combo->host.str=(char*)sctx->host,
combo->user.str,FALSE)))
-    goto found_acl;
-  if ((au= find_acl_user(combo->host.str=(char*)sctx->ip,
combo->user.str,FALSE)))
-    goto found_acl;
-  if((au= find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE)))
-    goto found_acl;
+    VOID(pthread_mutex_lock(&acl_cache->lock));
 
-  VOID(pthread_mutex_unlock(&acl_cache->lock));
-  DBUG_RETURN(TRUE);
+    for (int i = 0; host_name_variants[i]; ++i)
+    {
+      if ((au= find_acl_user(host_name_variants[i], user_name, FALSE)))
+      {
+        host_name= host_name_variants[i];
+        break;
+      }
+    }
 
- found_acl:
-  VOID(pthread_mutex_unlock(&acl_cache->lock));
+    if (host_name)
+    {
+      LEX_STRING host_name_str= { (char *) host_name, strlen(host_name) };
+      host_name_str.str= thd->strmake(host_name_str.str,
+                                      host_name_str.length);
+
+      combo->host_name.set(thd, &host_name_str);
+    }
+
+    VOID(pthread_mutex_unlock(&acl_cache->lock));
+
+    if (!host_name)
+      DBUG_RETURN(TRUE);
+  }
 
   bzero((char*)tables, sizeof(TABLE_LIST));
   user_list.empty();
@@ -5674,12 +5793,6 @@ bool sp_grant_privileges(THD *thd, const
   tables->db= (char*)sp_db;
   tables->table_name= tables->alias= (char*)sp_name;
 
-  combo->host.length= strlen(combo->host.str);
-  combo->user.length= strlen(combo->user.str);
-  combo->host.str= thd->strmake(combo->host.str,combo->host.length);
-  combo->user.str= thd->strmake(combo->user.str,combo->user.length);
-
-
   if(au && au->salt_len)
   {
     if (au->salt_len == SCRAMBLE_LENGTH)
@@ -5701,8 +5814,8 @@ bool sp_grant_privileges(THD *thd, const
   }
   else
   {
-    combo->password.str= (char*)"";
-    combo->password.length= 0;
+    combo->password.str= (char *) "";
+    combo->password.length= 1;
   }
 
   if (user_list.push_back(combo))
@@ -5712,7 +5825,7 @@ bool sp_grant_privileges(THD *thd, const
   bzero((char*) &thd->lex->mqh, sizeof(thd->lex->mqh));
 
   result= mysql_routine_grant(thd, tables, is_proc, user_list,
-  				DEFAULT_CREATE_PROC_ACLS, 0, 1);
+                              DEFAULT_CREATE_PROC_ACLS, 0, 1);
   DBUG_RETURN(result);
 }
 
@@ -5723,9 +5836,9 @@ bool sp_grant_privileges(THD *thd, const
 
 #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
 template class List_iterator<LEX_COLUMN>;
-template class List_iterator<LEX_USER>;
+template class List_iterator<Lex_user>;
 template class List<LEX_COLUMN>;
-template class List<LEX_USER>;
+template class List<Lex_user>;
 #endif
 
 #endif /*NO_EMBEDDED_ACCESS_CHECKS */

--- 1.50/sql/sql_acl.h	2006-07-28 20:03:15 +04:00
+++ 1.51/sql/sql_acl.h	2006-07-28 20:03:15 +04:00
@@ -188,13 +188,13 @@ bool check_change_password(THD *thd, con
                            char *password, uint password_len);
 bool change_password(THD *thd, const char *host, const char *user,
 		     char *password);
-bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
+bool mysql_grant(THD *thd, const char *db, List <Lex_user> &user_list,
                  ulong rights, bool revoke);
-bool mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list,
+bool mysql_table_grant(THD *thd, TABLE_LIST *table, List <Lex_user> &user_list,
                        List <LEX_COLUMN> &column_list, ulong rights,
                        bool revoke);
 bool mysql_routine_grant(THD *thd, TABLE_LIST *table, bool is_proc,
-			 List <LEX_USER> &user_list, ulong rights,
+			 List <Lex_user> &user_list, ulong rights,
 			 bool revoke, bool no_error);
 my_bool grant_init();
 void grant_free(void);
@@ -216,13 +216,13 @@ ulong get_table_grant(THD *thd, TABLE_LI
 ulong get_column_grant(THD *thd, GRANT_INFO *grant,
                        const char *db_name, const char *table_name,
                        const char *field_name);
-bool mysql_show_grants(THD *thd, LEX_USER *user);
+bool mysql_show_grants(THD *thd, Lex_user *user);
 void get_privilege_desc(char *to, uint max_length, ulong access);
 void get_mqh(const char *user, const char *host, USER_CONN *uc);
-bool mysql_create_user(THD *thd, List <LEX_USER> &list);
-bool mysql_drop_user(THD *thd, List <LEX_USER> &list);
-bool mysql_rename_user(THD *thd, List <LEX_USER> &list);
-bool mysql_revoke_all(THD *thd, List <LEX_USER> &list);
+bool mysql_create_user(THD *thd, List <Lex_user> &list);
+bool mysql_drop_user(THD *thd, List <Lex_user> &list);
+bool mysql_rename_user(THD *thd, List <Lex_user> &list);
+bool mysql_revoke_all(THD *thd, List <Lex_user> &list);
 void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
                                      const char *db, const char *table);
 bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,

--- 1.239/sql/sql_class.cc	2006-07-28 20:03:15 +04:00
+++ 1.240/sql/sql_class.cc	2006-07-28 20:03:15 +04:00
@@ -2199,3 +2199,28 @@ void xid_cache_delete(XID_STATE *xid_sta
   pthread_mutex_unlock(&LOCK_xid_cache);
 }
 
+
+/**************************************************************************
+  Callbacks for parse_user() in MySQL-server.
+**************************************************************************/
+
+C_MODE_START
+
+void on_user_name_truncated()
+{
+  push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+                      ER_USER_NAME_TRUNCATED,
+                      ER(ER_USER_NAME_TRUNCATED),
+                      USERNAME_LENGTH);
+}
+
+
+void on_host_name_truncated()
+{
+  push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+                      ER_HOST_NAME_TRUNCATED,
+                      ER(ER_HOST_NAME_TRUNCATED),
+                      HOSTNAME_LENGTH);
+}
+
+C_MODE_END

--- 1.293/sql/sql_class.h	2006-07-28 20:03:15 +04:00
+++ 1.294/sql/sql_class.h	2006-07-28 20:03:15 +04:00
@@ -2154,3 +2154,12 @@ public:
 /* Functions in sql_class.cc */
 
 void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var);
+
+/* Callbacks for parse_user() in MySQL-server. */
+
+C_MODE_START
+
+extern void on_user_name_truncated();
+extern void on_host_name_truncated();
+
+C_MODE_END

--- 1.223/sql/sql_lex.h	2006-07-28 20:03:15 +04:00
+++ 1.224/sql/sql_lex.h	2006-07-28 20:03:15 +04:00
@@ -830,7 +830,7 @@ typedef struct st_lex : public Query_tab
   select_result *result;
   Item *default_value, *on_update_value;
   LEX_STRING comment, ident;
-  LEX_USER *grant_user;
+  Lex_user *grant_user;
   XID *xid;
   gptr yacc_yyss,yacc_yyvs;
   THD *thd;
@@ -844,12 +844,12 @@ typedef struct st_lex : public Query_tab
     The definer of the object being created (view, trigger, stored routine).
     I.e. the value of DEFINER clause.
   */
-  LEX_USER *definer;
+  Lex_user *definer;
 
   List<key_part_spec> col_list;
   List<key_part_spec> ref_list;
   List<String>	      interval_list;
-  List<LEX_USER>      users_list;
+  List<Lex_user>      users_list;
   List<LEX_COLUMN>    columns;
   List<Key>	      key_list;
   List<create_field>  create_list;

--- 1.561/sql/sql_parse.cc	2006-07-28 20:03:15 +04:00
+++ 1.562/sql/sql_parse.cc	2006-07-28 20:03:16 +04:00
@@ -731,24 +731,28 @@ end:
 }
 
 
-static void reset_mqh(LEX_USER *lu, bool get_them= 0)
+static void reset_mqh(Lex_user *lu, bool get_them= 0)
 {
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
   (void) pthread_mutex_lock(&LOCK_user_conn);
   if (lu)  // for GRANT
   {
     USER_CONN *uc;
-    uint temp_len=lu->user.length+lu->host.length+2;
+    uint temp_len= lu->user_name.get_length() + lu->host_name.get_length() + 2;
     char temp_user[USER_HOST_BUFF_SIZE];
 
-    memcpy(temp_user,lu->user.str,lu->user.length);
-    memcpy(temp_user+lu->user.length+1,lu->host.str,lu->host.length);
-    temp_user[lu->user.length]='\0'; temp_user[temp_len-1]=0;
+    memcpy(temp_user,lu->user_name.get_c_str(), lu->user_name.get_length());
+    memcpy(temp_user + lu->user_name.get_length() + 1,
+           lu->host_name.get_c_str(), lu->host_name.get_length());
+
+    temp_user[lu->user_name.get_length()]= '\0';
+    temp_user[temp_len - 1]= 0;
+
     if ((uc = (struct  user_conn *) hash_search(&hash_user_connections,
 						(byte*) temp_user, temp_len)))
     {
       uc->questions=0;
-      get_mqh(temp_user,&temp_user[lu->user.length+1],uc);
+      get_mqh(temp_user,&temp_user[lu->user_name.get_length() + 1], uc);
       uc->updates=0;
       uc->conn_per_hour=0;
     }
@@ -3898,27 +3902,29 @@ end_with_restore_list:
 
     if (thd->security_ctx->user)              // If not replication
     {
-      LEX_USER *user, *tmp_user;
+      Lex_user *user, *tmp_user;
 
-      List_iterator <LEX_USER> user_list(lex->users_list);
+      List_iterator <Lex_user> user_list(lex->users_list);
       while ((tmp_user= user_list++))
       {
         if (!(user= get_current_user(thd, tmp_user)))
           goto error;
         if (specialflag & SPECIAL_NO_RESOLVE &&
-            hostname_requires_resolving(user->host.str))
+            hostname_requires_resolving(user->host_name.get_c_str()))
           push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                               ER_WARN_HOSTNAME_WONT_WORK,
                               ER(ER_WARN_HOSTNAME_WONT_WORK),
-                              user->host.str);
+                              user->host_name.get_c_str());
         // Are we trying to change a password of another user
-        DBUG_ASSERT(user->host.str != 0);
-        if (strcmp(thd->security_ctx->user, user->user.str) ||
+        DBUG_ASSERT(user->host_name.get_c_str() != 0);
+        if (strcmp(thd->security_ctx->user, user->user_name.get_c_str()) ||
             my_strcasecmp(system_charset_info,
-                          user->host.str, thd->security_ctx->host_or_ip))
+                          user->host_name.get_c_str(),
+                          thd->security_ctx->host_or_ip))
         {
           // TODO: use check_change_password()
-          if (is_acl_user(user->host.str, user->user.str) &&
+          if (is_acl_user(user->host_name.get_c_str(),
+                          user->user_name.get_c_str()) &&
               user->password.str &&
               check_access(thd, UPDATE_ACL,"mysql",0,1,1,0))
           {
@@ -3985,8 +3991,8 @@ end_with_restore_list:
 	}
 	if (lex->sql_command == SQLCOM_GRANT)
 	{
-	  List_iterator <LEX_USER> str_list(lex->users_list);
-	  LEX_USER *user, *tmp_user;
+	  List_iterator <Lex_user> str_list(lex->users_list);
+	  Lex_user *user, *tmp_user;
 	  while ((tmp_user=str_list++))
           {
             if (!(user= get_current_user(thd, tmp_user)))
@@ -4048,11 +4054,12 @@ end_with_restore_list:
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
   case SQLCOM_SHOW_GRANTS:
   {
-    LEX_USER *grant_user= get_current_user(thd, lex->grant_user);
+    Lex_user *grant_user= get_current_user(thd, lex->grant_user);
     if (!grant_user)
       goto error;
     if ((thd->security_ctx->priv_user &&
-	 !strcmp(thd->security_ctx->priv_user, grant_user->user.str)) ||
+        !strcmp(thd->security_ctx->priv_user,
+                grant_user->user_name.get_c_str())) ||
 	!check_access(thd, SELECT_ACL, "mysql",0,1,0,0))
     {
       res = mysql_show_grants(thd, grant_user);
@@ -4302,9 +4309,10 @@ end_with_restore_list:
       routine under another user one must have SUPER privilege).
     */
     
-    else if (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
+    else if (strcmp(lex->definer->user_name.get_c_str(),
+                    thd->security_ctx->priv_user) ||
         my_strcasecmp(system_charset_info,
-                      lex->definer->host.str,
+                      lex->definer->host_name.get_c_str(),
                       thd->security_ctx->priv_host))
     {
       if (check_global_access(thd, SUPER_ACL))
@@ -4319,15 +4327,15 @@ end_with_restore_list:
     /* Check that the specified definer exists. Emit a warning if not. */
 
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
-    if (!is_acl_user(lex->definer->host.str,
-                     lex->definer->user.str))
+    if (!is_acl_user(lex->definer->host_name.get_c_str(),
+                     lex->definer->user_name.get_c_str()))
     {
       push_warning_printf(thd,
                           MYSQL_ERROR::WARN_LEVEL_NOTE,
                           ER_NO_SUCH_USER,
                           ER(ER_NO_SUCH_USER),
-                          lex->definer->user.str,
-                          lex->definer->host.str);
+                          lex->definer->user_name.get_c_str(),
+                          lex->definer->host_name.get_c_str());
     }
 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
 
@@ -6698,7 +6706,7 @@ bool reload_acl_and_cache(THD *thd, ulon
       my_pthread_setspecific_ptr(THR_THD,  0);
       thd= 0;
     }
-    reset_mqh((LEX_USER *)NULL, TRUE);
+    reset_mqh((Lex_user *)NULL, TRUE);
   }
 #endif
   if (options & REFRESH_LOG)
@@ -6822,7 +6830,7 @@ bool reload_acl_and_cache(THD *thd, ulon
  }
 #endif
  if (options & REFRESH_USER_RESOURCES)
-   reset_mqh((LEX_USER *) NULL);
+   reset_mqh((Lex_user *) NULL);
  *write_to_binlog= tmp_write_to_binlog;
  return result;
 }
@@ -7427,22 +7435,21 @@ Item *negate_expression(THD *thd, Item *
 /*
   Set the specified definer to the default value, which is the current user in
   the thread.
- 
+
   SYNOPSIS
     get_default_definer()
     thd       [in] thread handler
     definer   [out] definer
 */
- 
-void get_default_definer(THD *thd, LEX_USER *definer)
-{
-  const Security_context *sctx= thd->security_ctx;
 
-  definer->user.str= (char *) sctx->priv_user;
-  definer->user.length= strlen(definer->user.str);
+void get_default_definer(THD *thd, Lex_user *definer)
+{
+  LEX_STRING user_name_str= { (char *) thd->security_ctx->priv_user,
+                              strlen(thd->security_ctx->priv_user) };
+  LEX_STRING host_name_str= { (char *) thd->security_ctx->priv_host,
+                              strlen(thd->security_ctx->priv_host) };
 
-  definer->host.str= (char *) sctx->priv_host;
-  definer->host.length= strlen(definer->host.str);
+  definer->set(thd, &user_name_str, &host_name_str, NULL);
 }
 
 
@@ -7455,15 +7462,15 @@ void get_default_definer(THD *thd, LEX_U
 
   RETURN
     On success, return a valid pointer to the created and initialized
-    LEX_USER, which contains definer information.
+    Lex_user, which contains definer information.
     On error, return 0.
 */
 
-LEX_USER *create_default_definer(THD *thd)
+Lex_user *create_default_definer(THD *thd)
 {
-  LEX_USER *definer;
+  Lex_user *definer;
 
-  if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
+  if (! (definer= (Lex_user*) thd->alloc(sizeof(Lex_user))))
     return 0;
 
   get_default_definer(thd, definer);
@@ -7473,37 +7480,6 @@ LEX_USER *create_default_definer(THD *th
 
 
 /*
-  Create definer with the given user and host names.
-
-  SYNOPSIS
-    create_definer()
-    thd         [in] thread handler
-    user_name   [in] user name
-    host_name   [in] host name
-
-  RETURN
-    On success, return a valid pointer to the created and initialized
-    LEX_USER, which contains definer information.
-    On error, return 0.
-*/
-
-LEX_USER *create_definer(THD *thd, LEX_STRING *user_name, LEX_STRING *host_name)
-{
-  LEX_USER *definer;
-
-  /* Create and initialize. */
-
-  if (! (definer= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
-    return 0;
-
-  definer->user= *user_name;
-  definer->host= *host_name;
-
-  return definer;
-}
-
-
-/*
   Retuns information about user or current user.
 
   SYNOPSIS
@@ -7513,18 +7489,18 @@ LEX_USER *create_definer(THD *thd, LEX_S
 
   RETURN
     On success, return a valid pointer to initialized
-    LEX_USER, which contains user information.
+    Lex_user, which contains user information.
     On error, return 0.
 */
 
-LEX_USER *get_current_user(THD *thd, LEX_USER *user)
+Lex_user *get_current_user(THD *thd, Lex_user *user)
 {
-  LEX_USER *curr_user;
-  if (!user->user.str)  // current_user
+  Lex_user *curr_user;
+  if (!user->user_name.get_c_str())  // current_user
   {
-    if (!(curr_user= (LEX_USER*) thd->alloc(sizeof(LEX_USER))))
+    if (!(curr_user= (Lex_user*) thd->alloc(sizeof(Lex_user))))
     {
-      my_error(ER_OUTOFMEMORY, MYF(0), sizeof(LEX_USER));
+      my_error(ER_OUTOFMEMORY, MYF(0), sizeof(Lex_user));
       return 0;
     }
     get_default_definer(thd, curr_user);

--- 1.324/sql/sql_show.cc	2006-07-28 20:03:16 +04:00
+++ 1.325/sql/sql_show.cc	2006-07-28 20:03:16 +04:00
@@ -1097,7 +1097,10 @@ void
 view_store_options(THD *thd, TABLE_LIST *table, String *buff)
 {
   append_algorithm(table, buff);
-  append_definer(thd, buff, &table->definer.user, &table->definer.host);
+  append_definer(thd, buff,
+                 table->definer.user_name.get_str(),
+                 table->definer.host_name.get_str());
+
   if (table->view_suid)
     buff->append(STRING_WITH_LEN("SQL SECURITY DEFINER "));
   else
@@ -1107,7 +1110,7 @@ view_store_options(THD *thd, TABLE_LIST 
 
 /*
   Append DEFINER clause to the given buffer.
-  
+
   SYNOPSIS
     append_definer()
     thd           [in] thread handle
@@ -3093,9 +3096,11 @@ static int get_schema_views_record(THD *
     ulong grant= SHOW_VIEW_ACL;
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
     char *save_table_name= tables->table_name;
-    if (!my_strcasecmp(system_charset_info, tables->definer.user.str,
+    if (!my_strcasecmp(system_charset_info,
+                       tables->definer.user_name.get_c_str(),
                        sctx->priv_user) &&
-        !my_strcasecmp(system_charset_info, tables->definer.host.str,
+        !my_strcasecmp(system_charset_info,
+                       tables->definer.host_name.get_c_str(),
                        sctx->priv_host))
       grant= SHOW_VIEW_ACL;
     else
@@ -3140,8 +3145,10 @@ static int get_schema_views_record(THD *
       table->field[5]->store(STRING_WITH_LEN("YES"), cs);
     else
       table->field[5]->store(STRING_WITH_LEN("NO"), cs);
-    definer_len= (strxmov(definer, tables->definer.user.str, "@",
-                          tables->definer.host.str, NullS) - definer);
+    definer_len= strxmov(definer,
+                         tables->definer.user_name.get_c_str(), "@",
+                         tables->definer.host_name.get_c_str(), NullS) -
+                 definer;
     table->field[6]->store(definer, definer_len, cs);
     if (tables->view_suid)
       table->field[7]->store(STRING_WITH_LEN("DEFINER"), cs);

--- 1.60/sql/sql_string.h	2006-07-28 20:03:16 +04:00
+++ 1.61/sql/sql_string.h	2006-07-28 20:03:16 +04:00
@@ -24,8 +24,6 @@
 #define NOT_FIXED_DEC			31
 #endif
 
-#define STRING_WITH_LEN(X)  ((const char*) X), ((uint) (sizeof(X) - 1))
-
 class String;
 int sortcmp(const String *a,const String *b, CHARSET_INFO *cs);
 String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);

--- 1.476/sql/sql_yacc.yy	2006-07-28 20:03:16 +04:00
+++ 1.477/sql/sql_yacc.yy	2006-07-28 20:03:16 +04:00
@@ -86,7 +86,7 @@ inline Item *is_truth_value(Item *A, boo
   key_part_spec *key_part;
   TABLE_LIST *table_list;
   udf_func *udf;
-  LEX_USER *lex_user;
+  Lex_user *lex_user;
   struct sys_var_with_base variable;
   enum enum_var_type var_type;
   Key::Keytype key_type;
@@ -6529,10 +6529,10 @@ show_param:
 	  {
 	    LEX *lex=Lex;
 	    lex->sql_command= SQLCOM_SHOW_GRANTS;
-	    LEX_USER *curr_user;
-            if (!(curr_user= (LEX_USER*) lex->thd->alloc(sizeof(st_lex_user))))
+	    Lex_user *curr_user;
+            if (!(curr_user= (Lex_user*) lex->thd->alloc(sizeof(Lex_user))))
               YYABORT;
-            bzero(curr_user, sizeof(st_lex_user));
+            bzero(curr_user, sizeof(Lex_user));
 	    lex->grant_user= curr_user;
 	  }
 	| GRANTS FOR_SYM user
@@ -6540,7 +6540,7 @@ show_param:
 	    LEX *lex=Lex;
 	    lex->sql_command= SQLCOM_SHOW_GRANTS;
 	    lex->grant_user=$3;
-	    lex->grant_user->password=null_lex_str;
+            lex->grant_user->reset_password();
 	  }
 	| CREATE DATABASE opt_if_not_exists ident
 	  {
@@ -7466,30 +7466,30 @@ ident_or_text:
 user:
 	ident_or_text
 	{
-	  THD *thd= YYTHD;
-	  if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
+          LEX_STRING host_name_str= { C_STRING_WITH_LEN("%") };
+
+	  if (!($$=(Lex_user*) YYTHD->alloc(sizeof(Lex_user))))
 	    YYABORT;
-	  $$->user = $1;
-	  $$->host.str= (char *) "%";
-	  $$->host.length= 1;
+
+          $$->set(YYTHD, &$1, &host_name_str, NULL);
 	}
 	| ident_or_text '@' ident_or_text
 	  {
-	    THD *thd= YYTHD;
-	    if (!($$=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
+	    if (!($$=(Lex_user*) YYTHD->alloc(sizeof(Lex_user))))
 	      YYABORT;
-	    $$->user = $1; $$->host=$3;
+
+            $$->set(YYTHD, &$1, &$3, NULL);
 	  }
 	| CURRENT_USER optional_braces
 	{
-          if (!($$=(LEX_USER*) YYTHD->alloc(sizeof(st_lex_user))))
+          if (!($$=(Lex_user*) YYTHD->alloc(sizeof(Lex_user))))
             YYABORT;
           /* 
-            empty LEX_USER means current_user and 
+            empty Lex_user means current_user and 
             will be handled in the  get_current_user() function
             later
           */
-          bzero($$, sizeof(LEX_USER));
+          bzero($$, sizeof(Lex_user));
 	};
 
 /* Keyword that we allow for identifiers (except SP labels) */
@@ -8020,8 +8020,10 @@ option_value:
 	| PASSWORD equal text_or_password
 	  {
 	    THD *thd=YYTHD;
-	    LEX_USER *user;
-	    LEX *lex= Lex;	    
+	    Lex_user *user;
+            LEX_STRING user_name_str= { thd->security_ctx->priv_user,
+                                        strlen(thd->security_ctx->priv_user) };
+	    LEX *lex= Lex;
             sp_pcontext *spc= lex->spcont;
 	    LEX_STRING pw;
 
@@ -8032,15 +8034,16 @@ option_value:
               my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str);
 	      YYABORT;
 	    }
-	    if (!(user=(LEX_USER*) thd->alloc(sizeof(LEX_USER))))
-	      YYABORT;
-	    user->host=null_lex_str;
-	    user->user.str=thd->security_ctx->priv_user;
-	    thd->lex->var_list.push_back(new set_var_password(user, $3));
+            thd->lex->var_list.push_back(
+              new set_var_password(thd, &user_name_str, NULL, $3));
 	  }
 	| PASSWORD FOR_SYM user equal text_or_password
 	  {
-	    Lex->var_list.push_back(new set_var_password($3,$5));
+            Lex->var_list.push_back(
+              new set_var_password(YYTHD,
+                                   $3->user_name.get_str(),
+                                   $3->host_name.get_str(),
+                                   $5));
 	  }
 	;
 
@@ -8569,12 +8572,13 @@ grant_list:
 grant_user:
 	user IDENTIFIED_SYM BY TEXT_STRING
 	{
-	   $$=$1; $1->password=$4;
+	   $$=$1;
+           $1->password= $4;
 	   if ($4.length)
 	   {
              if (YYTHD->variables.old_passwords)
              {
-               char *buff= 
+               char *buff=
                  (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
                if (buff)
                  make_scrambled_password_323(buff, $4.str);
@@ -8583,7 +8587,7 @@ grant_user:
              }
              else
              {
-               char *buff= 
+               char *buff=
                  (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
                if (buff)
                  make_scrambled_password(buff, $4.str);
@@ -8593,9 +8597,15 @@ grant_user:
 	  }
 	}
 	| user IDENTIFIED_SYM BY PASSWORD TEXT_STRING
-	  { $$= $1; $1->password= $5; }
+	  {
+            $$= $1;
+            $1->password= $5;
+          }
 	| user
-	  { $$= $1; $1->password= null_lex_str; }
+	  {
+            $$= $1;
+            $1->reset_password();
+          }
         ;
 
 
@@ -8954,7 +8964,7 @@ definer:
             from older master servers (i.e. to create non-suid trigger in this
             case).
            */
-          YYTHD->lex->definer= 0;
+          Lex->definer= NULL;
 	}
 	| DEFINER_SYM EQ CURRENT_USER optional_braces
 	{
@@ -8963,8 +8973,10 @@ definer:
 	}
 	| DEFINER_SYM EQ ident_or_text '@' ident_or_text
 	{
-          if (!(YYTHD->lex->definer= create_definer(YYTHD, &$3, &$5)))
+          if (!(Lex->definer= (Lex_user *) YYTHD->alloc(sizeof (Lex_user))))
             YYABORT;
+
+          Lex->definer->set(YYTHD, &$3, &$5, NULL);
 	}
 	;
 

--- 1.55/sql/structs.h	2006-07-28 20:03:16 +04:00
+++ 1.56/sql/structs.h	2006-07-28 20:03:16 +04:00
@@ -20,22 +20,6 @@
 struct st_table;
 class Field;
 
-typedef struct st_lex_string
-{
-  char *str;
-  uint length;
-} LEX_STRING;
-
-typedef struct st_lex_string_with_init :public st_lex_string
-{
-  st_lex_string_with_init(const char *str_arg, uint length_arg)
-  {
-    str= (char*) str_arg;
-    length= length_arg;
-  }
-} LEX_STRING_WITH_INIT;
-
-
 typedef struct st_date_time_format {
   uchar positions[8];
   char  time_separator;			/* Separator between hour and minute */
@@ -207,11 +191,6 @@ typedef struct show_var_st {
   char *value;
   SHOW_TYPE type;
 } SHOW_VAR;
-
-
-typedef struct	st_lex_user {
-  LEX_STRING user, host, password;
-} LEX_USER;
 
 
 /*

--- 1.229/sql/table.cc	2006-07-28 20:03:16 +04:00
+++ 1.230/sql/table.cc	2006-07-28 20:03:16 +04:00
@@ -1549,27 +1549,60 @@ bool get_field(MEM_ROOT *mem, Field *fie
 
   SYNOPSIS
     get_field()
-    mem   	MEM_ROOT for allocating
-    field 	Field for retrieving of string
+    mem	        [IN] MEM_ROOT for allocating
+    field	[IN] Field for retrieving of string
+    value       [OUT] Buffer for field value
 
   RETURN VALUES
-    NullS  string is empty
+    TRUE  out of memory
+    FALSE all ok
+*/
+
+bool get_field(MEM_ROOT *mem, Field *field, LEX_STRING *value)
+{
+  char buff[MAX_FIELD_WIDTH];
+  String str(buff, sizeof (buff), &my_charset_bin);
+
+  field->val_str(&str);
+  value->length= str.length();
+
+  if (!value->length)
+    return FALSE;
+
+  if (!(value->str= (char *) alloc_root(mem, value->length + 1)))
+    return TRUE;
+
+  memcpy(value->str, str.ptr(), value->length);
+  value->str[value->length]= 0;
+
+  return FALSE;
+}
+
+
+/*
+  Allocate string field in MEM_ROOT and return it as NULL-terminated string
+
+  SYNOPSIS
+    get_field()
+    mem	        MEM_ROOT for allocating
+    field	Field for retrieving of string
+
+  RETURN VALUES
+    NullS  string is empty or out-of-memory error
     #      pointer to NULL-terminated string value of field
 */
 
 char *get_field(MEM_ROOT *mem, Field *field)
 {
-  char buff[MAX_FIELD_WIDTH], *to;
-  String str(buff,sizeof(buff),&my_charset_bin);
-  uint length;
+  LEX_STRING value;
 
-  field->val_str(&str);
-  length= str.length();
-  if (!length || !(to= (char*) alloc_root(mem,length+1)))
+  if (get_field(mem, field, &value))
     return NullS;
-  memcpy(to,str.ptr(),(uint) length);
-  to[length]=0;
-  return to;
+
+  if (!value.length)
+    return NullS;
+
+  return value.str;
 }
 
 
@@ -2427,21 +2460,23 @@ bool st_table_list::prepare_view_securet
     DBUG_PRINT("info", ("This table is suid view => load contest"));
     DBUG_ASSERT(view && view_sctx);
     if (acl_getroot_no_password(view_sctx,
-                                definer.user.str,
-                                definer.host.str,
-                                definer.host.str,
+                                definer.user_name.get_c_str(),
+                                definer.host_name.get_c_str(),
+                                definer.host_name.get_c_str(),
                                 thd->db))
     {
       if (thd->lex->sql_command == SQLCOM_SHOW_CREATE)
       {
-        push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, 
-                            ER_NO_SUCH_USER, 
+        push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+                            ER_NO_SUCH_USER,
                             ER(ER_NO_SUCH_USER),
-                            definer.user.str, definer.host.str);
+                            definer.user_name.get_c_str(),
+                            definer.host_name.get_c_str());
       }
       else
       {
-        my_error(ER_NO_SUCH_USER, MYF(0), definer.user.str, definer.host.str);
+        my_error(ER_NO_SUCH_USER, MYF(0), definer.user_name.get_c_str(),
+                 definer.host_name.get_c_str());
         DBUG_RETURN(TRUE);
       }
     }
@@ -3024,3 +3059,94 @@ void st_table_list::reinit_before_use(TH
 template class List<String>;
 template class List_iterator<String>;
 #endif
+
+
+/**************************************************************************
+  User_name implementation.
+**************************************************************************/
+
+User_name::User_name()
+{
+  reset();
+}
+
+
+void User_name::set(THD *thd, LEX_STRING *user_name)
+{
+  if (!user_name)
+  {
+    reset();
+    return;
+  }
+
+  if (user_name->length > USERNAME_LENGTH)
+  {
+    user_name->str[USERNAME_LENGTH]= 0;
+    user_name->length= USERNAME_LENGTH;
+
+    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+                        ER_USER_NAME_TRUNCATED,
+                        ER(ER_USER_NAME_TRUNCATED),
+                        USERNAME_LENGTH);
+  }
+
+  value= *user_name;
+}
+
+
+/**************************************************************************
+  Host_name implementation.
+**************************************************************************/
+
+Host_name::Host_name()
+{
+  reset();
+}
+
+
+void Host_name::set(THD *thd, LEX_STRING *host_name)
+{
+  if (!host_name)
+  {
+    reset();
+    return;
+  }
+
+  if (host_name->length > HOSTNAME_LENGTH)
+  {
+    host_name->str[HOSTNAME_LENGTH]= 0;
+    host_name->length= HOSTNAME_LENGTH;
+
+    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+                        ER_HOST_NAME_TRUNCATED,
+                        ER(ER_HOST_NAME_TRUNCATED),
+                        HOSTNAME_LENGTH);
+  }
+
+  value= *host_name;
+}
+
+
+/**************************************************************************
+  Lex_user implementation.
+**************************************************************************/
+
+Lex_user::Lex_user()
+{
+  reset_password();
+}
+
+
+void Lex_user::set(THD *thd,
+                   LEX_STRING *user_name_arg,
+                   LEX_STRING *host_name_arg,
+                   LEX_STRING *password_arg)
+{
+  user_name.set(thd, user_name_arg);
+  host_name.set(thd, host_name_arg);
+
+  if (password_arg)
+    password= *password_arg;
+  else
+    reset_password();
+}

--- 1.131/sql/table.h	2006-07-28 20:03:16 +04:00
+++ 1.132/sql/table.h	2006-07-28 20:03:16 +04:00
@@ -24,6 +24,109 @@ class st_select_lex;
 class COND_EQUAL;
 class Security_context;
 
+
+class User_name
+{
+public:
+  User_name();
+
+public:
+  void set(THD *thd, LEX_STRING *user_name);
+
+  inline LEX_STRING *get_str()
+  {
+    return &value;
+  }
+
+  inline char *get_c_str()
+  {
+    return value.str;
+  }
+
+  inline const char *get_c_str() const
+  {
+    return value.str;
+  }
+
+  inline uint get_length() const
+  {
+    return value.length;
+  }
+
+  inline void reset()
+  {
+    value.str= NULL;
+    value.length= 0;
+  }
+
+private:
+  LEX_STRING value;
+};
+
+
+class Host_name
+{
+public:
+  Host_name();
+
+public:
+  void set(THD *thd, LEX_STRING *host_name);
+
+  inline LEX_STRING *get_str()
+  {
+    return &value;
+  }
+
+  inline char *get_c_str()
+  {
+    return value.str;
+  }
+
+  inline const char *get_c_str() const
+  {
+    return value.str;
+  }
+
+  inline uint get_length() const
+  {
+    return value.length;
+  }
+
+  inline void reset()
+  {
+    value.str= NULL;
+    value.length= 0;
+  }
+
+private:
+  LEX_STRING value;
+};
+
+
+class Lex_user
+{
+public:
+  Lex_user();
+
+public:
+  void set(THD *thd,
+           LEX_STRING *user_name_arg,
+           LEX_STRING *host_name_arg,
+           LEX_STRING *password_arg);
+
+  inline void reset_password()
+  {
+    password.str= NULL;
+    password.length= 0;
+  }
+
+public:
+  User_name user_name;
+  Host_name host_name;
+
+  LEX_STRING password;
+};
+
 /* Order clause list element */
 
 typedef struct st_order {
@@ -578,7 +681,7 @@ typedef struct st_table_list
   LEX_STRING	view_db;		/* saved view database */
   LEX_STRING	view_name;		/* saved view name */
   LEX_STRING	timestamp;		/* GMT time stamp of last operation */
-  st_lex_user   definer;                /* definer of view */
+  Lex_user      definer;                /* definer of view */
   ulonglong	file_version;		/* version of file's field set */
   ulonglong     updatable_view;         /* VIEW can be updated */
   ulonglong	revision;		/* revision control number */

--- 1.65/sql/share/errmsg.txt	2006-07-28 20:03:16 +04:00
+++ 1.66/sql/share/errmsg.txt	2006-07-28 20:03:16 +04:00
@@ -5621,3 +5621,7 @@ ER_TABLE_CANT_HANDLE_SPKEYS
         eng "The used table type doesn't support SPATIAL indexes"
 ER_NO_TRIGGERS_ON_SYSTEM_SCHEMA
 	eng "Triggers can not be created on system tables"
+ER_USER_NAME_TRUNCATED
+				eng "The user name has been truncated to %d symbols"
+ER_HOST_NAME_TRUNCATED
+				eng "The host name has been truncated to %d symbols"
--- New file ---
+++ BitKeeper/etc/collapsed	06/07/28 17:35:18
44c793b7N8P7mznmNrhnNJOzRGevvA

--- New file ---
+++ sql/structs.cc	06/07/28 20:03:07
/* Copyright (C) 2006 MySQL AB

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#include "mysql_priv.h"

/**************************************************************************
  User_name implementation.
**************************************************************************/

User_name::User_name()
{
  reset();
}


void User_name::set(THD *thd, LEX_STRING *user_name)
{
  if (!user_name)
  {
    reset();
    return;
  }

  if (user_name->length > USERNAME_LENGTH)
  {
    user_name->str[USERNAME_LENGTH]= 0;
    user_name->length= USERNAME_LENGTH;

    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
                        ER_USER_NAME_TRUNCATED,
                        ER(ER_USER_NAME_TRUNCATED),
                        USERNAME_LENGTH);
  }

  value= *user_name;
}


/**************************************************************************
  Host_name implementation.
**************************************************************************/

Host_name::Host_name()
{
  reset();
}


void Host_name::set(THD *thd, LEX_STRING *host_name)
{
  if (!host_name)
  {
    reset();
    return;
  }

  if (host_name->length > HOSTNAME_LENGTH)
  {
    host_name->str[HOSTNAME_LENGTH]= 0;
    host_name->length= HOSTNAME_LENGTH;

    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
                        ER_HOST_NAME_TRUNCATED,
                        ER(ER_HOST_NAME_TRUNCATED),
                        HOSTNAME_LENGTH);
  }

  value= *host_name;
}


/**************************************************************************
  LEX_USER implementation.
**************************************************************************/

LEX_USER::LEX_USER()
{
  reset_password();
}


void LEX_USER::set(THD *thd,
                   LEX_STRING *user_name_arg,
                   LEX_STRING *host_name_arg,
                   LEX_STRING *password_arg)
{
  user_name.set(thd, user_name_arg);
  host_name.set(thd, host_name_arg);

  if (password_arg)
    password= *password_arg;
  else
    reset_password();
}


--- 1.1/include/my_user.h	2006-07-28 20:03:16 +04:00
+++ 1.2/include/my_user.h	2006-07-28 20:03:16 +04:00
@@ -23,12 +23,17 @@
 #define _my_user_h_
 
 #include <my_global.h>
+#include <m_string.h>
 
 C_MODE_START
 
-void parse_user(const char *user_id_str, uint user_id_len,
-                char *user_name_str, uint *user_name_len,
-                char *host_name_str, uint *host_name_len);
+typedef void (*parse_user_cb)(void);
+
+void parse_user(const LEX_STRING *user_id,
+                LEX_STRING *user_name,
+                LEX_STRING *host_name,
+                parse_user_cb on_user_name_truncated,
+                parse_user_cb on_host_name_truncated);
 
 C_MODE_END
 

--- 1.1/sql-common/my_user.c	2006-07-28 20:03:16 +04:00
+++ 1.2/sql-common/my_user.c	2006-07-28 20:03:16 +04:00
@@ -22,36 +22,54 @@
   Parse user value to user name and host name parts.
 
   SYNOPSIS
-    user_id_str     [IN]  User value string (the source).
-    user_id_len     [IN]  Length of the user value.
-    user_name_str   [OUT] Buffer to store user name part.
-                          Must be not less than USERNAME_LENGTH + 1.
-    user_name_len   [OUT] A place to store length of the user name part.
-    host_name_str   [OUT] Buffer to store host name part.
-                          Must be not less than HOSTNAME_LENGTH + 1.
-    host_name_len   [OUT] A place to store length of the host name part.
+    user_id                 [IN]  User value string (the source).
+    user_name               [IN/OUT] Buffer to store user name part.
+                             IN: Maximal possible length of the user name part.
+                             OUT: A place to store length of the user name part.
+    host_name               [IN/OUT] Buffer to store host name part.
+                             IN: Maximal possible length of the host name part.
+                             OUT: A place to store length of the host name part.
+    on_user_name_truncated  [IN] Function to report about user name truncation.
+    on_host_name_truncated  [IN] Function to report about host name truncation.
 */
 
-void parse_user(const char *user_id_str, uint user_id_len,
-                char *user_name_str, uint *user_name_len,
-                char *host_name_str, uint *host_name_len)
+void parse_user(const LEX_STRING *user_id,
+                LEX_STRING *user_name,
+                LEX_STRING *host_name,
+                parse_user_cb on_user_name_truncated,
+                parse_user_cb on_host_name_truncated)
 {
-  char *p= strrchr(user_id_str, '@');
+  char *p= strrchr(user_id->str, '@');
 
   if (!p)
   {
-    *user_name_len= 0;
-    *host_name_len= 0;
+    user_name->length= 0;
+    host_name->length= 0;
   }
   else
   {
-    *user_name_len= p - user_id_str;
-    *host_name_len= user_id_len - *user_name_len - 1;
+    uint max_user_name_len= user_name->length;
+    uint max_host_name_len= host_name->length;
 
-    memcpy(user_name_str, user_id_str, *user_name_len);
-    memcpy(host_name_str, p + 1, *host_name_len);
+    user_name->length= p - user_id->str;
+    host_name->length= user_id->length - user_name->length - 1;
+
+    if (user_name->length > max_user_name_len)
+    {
+      user_name->length= max_user_name_len;
+      on_user_name_truncated();
+    }
+
+    if (host_name->length > max_host_name_len)
+    {
+      host_name->length= max_host_name_len;
+      on_host_name_truncated();
+    }
+
+    memcpy(user_name->str, user_id->str, user_name->length);
+    memcpy(host_name->str, p + 1, host_name->length);
   }
 
-  user_name_str[*user_name_len]= 0;
-  host_name_str[*host_name_len]= 0;
+  user_name->str[user_name->length]= 0;
+  host_name->str[host_name->length]= 0;
 }

--- 1.27/sql/spatial.cc	2006-07-28 20:03:16 +04:00
+++ 1.28/sql/spatial.cc	2006-07-28 20:03:16 +04:00
@@ -34,8 +34,11 @@ static Geometry::Class_info **ci_collect
 
 Geometry::Class_info::Class_info(const char *name, int type_id,
 					 void(*create_func)(void *)):
-  m_name(name, strlen(name)), m_type_id(type_id), m_create_func(create_func)
+  m_type_id(type_id), m_create_func(create_func)
 {
+  m_name.str= (char *) name;
+  m_name.length= strlen(name);
+
   ci_collection[type_id]= this;
 }
 

--- 1.20/sql/spatial.h	2006-07-28 20:03:16 +04:00
+++ 1.21/sql/spatial.h	2006-07-28 20:03:16 +04:00
@@ -200,7 +200,7 @@ public:
   class Class_info
   {
   public:
-    LEX_STRING_WITH_INIT m_name;
+    LEX_STRING m_name;
     int m_type_id;
     void (*m_create_func)(void *);
     Class_info(const char *name, int type_id, void(*create_func)(void *));

--- 1.162/mysql-test/r/view.result	2006-07-28 20:03:16 +04:00
+++ 1.163/mysql-test/r/view.result	2006-07-28 20:03:16 +04:00
@@ -2736,3 +2736,30 @@ m	e
 1	b
 DROP VIEW v1;
 DROP TABLE IF EXISTS t1,t2;
+DROP TABLE IF EXISTS t1;
+DROP VIEW IF EXISTS v1;
+DROP VIEW IF EXISTS v2;
+CREATE TABLE t1(a INT, b INT);
+CREATE DEFINER=1234567890abcdefGHIKL@localhost
+VIEW v1 AS SELECT a FROM t1;
+Warnings:
+Note	1466	The user name has been truncated to 16 symbols
+Note	1449	There is no '1234567890abcdef'@'localhost' registered
+CREATE
DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
+VIEW v2 AS SELECT b FROM t1;
+Warnings:
+Note	1467	The host name has been truncated to 60 symbols
+Note	1449	There is no
'some_user_name'@'1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij'
registered
+SHOW CREATE VIEW v1;
+View	Create View
+v1	CREATE ALGORITHM=UNDEFINED DEFINER=`1234567890abcdef`@`localhost` SQL SECURITY DEFINER
VIEW `v1` AS select `t1`.`a` AS `a` from `t1`
+Warnings:
+Note	1449	There is no '1234567890abcdef'@'localhost' registered
+SHOW CREATE VIEW v2;
+View	Create View
+v2	CREATE ALGORITHM=UNDEFINED
DEFINER=`some_user_name`@`1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij`
SQL SECURITY DEFINER VIEW `v2` AS select `t1`.`b` AS `b` from `t1`
+Warnings:
+Note	1449	There is no
'some_user_name'@'1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij'
registered
+DROP TABLE t1;
+DROP VIEW v1;
+DROP VIEW v2;

--- 1.147/mysql-test/t/view.test	2006-07-28 20:03:16 +04:00
+++ 1.148/mysql-test/t/view.test	2006-07-28 20:03:16 +04:00
@@ -2596,3 +2596,35 @@ SELECT * FROM t2;
 
 DROP VIEW v1;
 DROP TABLE IF EXISTS t1,t2;
+
+
+#
+# Test for BUG#16899: Possible buffer overflow in handling of DEFINER-clause.
+#
+
+# Prepare.
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP VIEW IF EXISTS v1;
+DROP VIEW IF EXISTS v2;
+--enable_warnings
+
+CREATE TABLE t1(a INT, b INT);
+
+CREATE DEFINER=1234567890abcdefGHIKL@localhost
+  VIEW v1 AS SELECT a FROM t1;
+
+CREATE
DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
+  VIEW v2 AS SELECT b FROM t1;
+
+# Test.
+
+SHOW CREATE VIEW v1;
+SHOW CREATE VIEW v2;
+
+# Cleanup.
+
+DROP TABLE t1;
+DROP VIEW v1;
+DROP VIEW v2;

--- 1.90/sql/sql_view.cc	2006-07-28 20:03:16 +04:00
+++ 1.91/sql/sql_view.cc	2006-07-28 20:03:16 +04:00
@@ -235,10 +235,10 @@ bool mysql_create_view(THD *thd,
       - same as current user
       - current user has SUPER_ACL
   */
-  if (strcmp(lex->definer->user.str,
+  if (strcmp(lex->definer->user_name.get_c_str(),
              thd->security_ctx->priv_user) != 0 ||
       my_strcasecmp(system_charset_info,
-                    lex->definer->host.str,
+                    lex->definer->host_name.get_c_str(),
                     thd->security_ctx->priv_host) != 0)
   {
     if (!(thd->security_ctx->master_access & SUPER_ACL))
@@ -249,14 +249,14 @@ bool mysql_create_view(THD *thd,
     }
     else
     {
-      if (!is_acl_user(lex->definer->host.str,
-                       lex->definer->user.str))
+      if (!is_acl_user(lex->definer->host_name.get_c_str(),
+                       lex->definer->user_name.get_c_str()))
       {
         push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
                             ER_NO_SUCH_USER,
                             ER(ER_NO_SUCH_USER),
-                            lex->definer->user.str,
-                            lex->definer->host.str);
+                            lex->definer->user_name.get_c_str(),
+                            lex->definer->host_name.get_c_str());
       }
     }
   }
@@ -536,10 +536,10 @@ static File_option view_parameters[]=
   offsetof(TABLE_LIST, algorithm),
   FILE_OPTIONS_ULONGLONG},
  {{(char*) STRING_WITH_LEN("definer_user")},
-  offsetof(TABLE_LIST, definer.user),
+  offsetof(TABLE_LIST, definer.user_name),
   FILE_OPTIONS_STRING},
  {{(char*) STRING_WITH_LEN("definer_host")},
-  offsetof(TABLE_LIST, definer.host),
+  offsetof(TABLE_LIST, definer.host_name),
   FILE_OPTIONS_STRING},
  {{(char*) STRING_WITH_LEN("suid")},
   offsetof(TABLE_LIST, view_suid),
@@ -688,8 +688,8 @@ static int mysql_register_view(THD *thd,
     lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
   }
   view->algorithm= lex->create_view_algorithm;
-  view->definer.user= lex->definer->user;
-  view->definer.host= lex->definer->host;
+  view->definer.user_name= lex->definer->user_name;
+  view->definer.host_name= lex->definer->host_name;
   view->view_suid= lex->create_view_suid;
   view->with_check= lex->create_view_check;
   if ((view->updatable_view= (can_be_merged &&
@@ -834,8 +834,8 @@ bool mysql_make_view(THD *thd, File_pars
     table->timestamp.str= table->timestamp_buffer;
   /* prepare default values for old format */
   table->view_suid= TRUE;
-  table->definer.user.str= table->definer.host.str= 0;
-  table->definer.user.length= table->definer.host.length= 0;
+  table->definer.user_name.set(thd, NULL);
+  table->definer.host_name.set(thd, NULL);
 
   /*
     TODO: when VIEWs will be stored in cache, table mem_root should
@@ -848,11 +848,11 @@ bool mysql_make_view(THD *thd, File_pars
   /*
     check old format view .frm
   */
-  if (!table->definer.user.str)
+  if (!table->definer.user_name.get_c_str())
   {
-    DBUG_ASSERT(!table->definer.host.str &&
-                !table->definer.user.length &&
-                !table->definer.host.length);
+    DBUG_ASSERT(!table->definer.host_name.get_c_str() &&
+                !table->definer.user_name.get_length() &&
+                !table->definer.host_name.get_length());
     push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
                         ER_VIEW_FRM_NO_USER, ER(ER_VIEW_FRM_NO_USER),
                         table->db, table->table_name);

--- 1.43/mysql-test/r/trigger.result	2006-07-28 20:03:16 +04:00
+++ 1.44/mysql-test/r/trigger.result	2006-07-28 20:03:16 +04:00
@@ -1089,4 +1089,25 @@ begin
 set @a:= 1;
 end|
 ERROR HY000: Triggers can not be created on system tables
+use test|
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+CREATE TABLE t1(c INT);
+CREATE TABLE t2(c INT);
+CREATE DEFINER=1234567890abcdefGHIKL@localhost
+TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a = 1;
+Warnings:
+Note	1466	The user name has been truncated to 16 symbols
+Note	1449	There is no '1234567890abcdef'@'localhost' registered
+CREATE
DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
+TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW SET @a = 2;
+Warnings:
+Note	1467	The host name has been truncated to 60 symbols
+Note	1449	There is no
'some_user_name'@'1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij'
registered
+INSERT INTO t1 VALUES(1);
+ERROR HY000: There is no '1234567890abcdef'@'localhost' registered
+INSERT INTO t2 VALUES(2);
+ERROR HY000: There is no
'some_user_name'@'1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij'
registered
+DROP TABLE t1;
+DROP TABLE t2;
 End of 5.0 tests

--- 1.49/mysql-test/t/trigger.test	2006-07-28 20:03:16 +04:00
+++ 1.50/mysql-test/t/trigger.test	2006-07-28 20:03:16 +04:00
@@ -1301,6 +1301,42 @@ create trigger wont_work after update on
 begin
  set @a:= 1;
 end|
+use test|
 delimiter ;|
+
+
+#
+# Test for BUG#16899: Possible buffer overflow in handling of DEFINER-clause.
+#
+
+# Prepare.
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+--enable_warnings
+
+CREATE TABLE t1(c INT);
+CREATE TABLE t2(c INT);
+
+CREATE DEFINER=1234567890abcdefGHIKL@localhost
+  TRIGGER t1_bi BEFORE INSERT ON t1 FOR EACH ROW SET @a = 1;
+
+CREATE
DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
+  TRIGGER t2_bi BEFORE INSERT ON t2 FOR EACH ROW SET @a = 2;
+
+# Test.
+
+--error ER_NO_SUCH_USER
+INSERT INTO t1 VALUES(1);
+
+--error ER_NO_SUCH_USER
+INSERT INTO t2 VALUES(2);
+
+# Cleanup.
+
+DROP TABLE t1;
+DROP TABLE t2;
+
 
 --echo End of 5.0 tests

--- 1.54/sql/sql_trigger.cc	2006-07-28 20:03:16 +04:00
+++ 1.55/sql/sql_trigger.cc	2006-07-28 20:03:16 +04:00
@@ -158,11 +158,13 @@ bool mysql_create_or_drop_trigger(THD *t
 {
   TABLE *table;
   bool result= TRUE;
-  LEX_STRING definer_user;
-  LEX_STRING definer_host;
+  String stmt_query;
 
   DBUG_ENTER("mysql_create_or_drop_trigger");
 
+  /* Charset of the buffer for statement must be system one. */
+  stmt_query.set_charset(system_charset_info);
+
   /*
     QQ: This function could be merged in mysql_alter_table() function
     But do we want this ?
@@ -264,8 +266,8 @@ bool mysql_create_or_drop_trigger(THD *t
   }
 
   result= (create ?
-           table->triggers->create_trigger(thd, tables, &definer_user,
&definer_host):
-           table->triggers->drop_trigger(thd, tables));
+           table->triggers->create_trigger(thd, tables, &stmt_query):
+           table->triggers->drop_trigger(thd, tables, &stmt_query));
 
 end:
   VOID(pthread_mutex_unlock(&LOCK_open));
@@ -277,32 +279,9 @@ end:
     {
       thd->clear_error();
 
-      String log_query(thd->query, thd->query_length, system_charset_info);
-
-      if (create)
-      {
-        log_query.set((char *) 0, 0, system_charset_info); /* reset log_query */
-
-        log_query.append(STRING_WITH_LEN("CREATE "));
-
-        if (definer_user.str && definer_host.str)
-        {
-          /*
-            Append definer-clause if the trigger is SUID (a usual trigger in
-            new MySQL versions).
-          */
-
-          append_definer(thd, &log_query, &definer_user, &definer_host);
-        }
-
-        log_query.append(thd->lex->stmt_definition_begin,
-                         (char *)thd->lex->sphead->m_body_begin -
-                         thd->lex->stmt_definition_begin +
-                         thd->lex->sphead->m_body.length);
-      }
-
       /* Such a statement can always go directly to binlog, no trans cache. */
-      Query_log_event qinfo(thd, log_query.ptr(), log_query.length(), 0, FALSE);
+      Query_log_event qinfo(thd, stmt_query.ptr(), stmt_query.length(), 0,
+                            FALSE);
       mysql_bin_log.write(&qinfo);
     }
 
@@ -322,22 +301,8 @@ end:
                      LEX)
       tables       - table list containing one open table for which the
                      trigger is created.
-      definer_user - [out] after a call it points to 0-terminated string or
-                     contains the NULL-string:
-                       - 0-terminated is returned if the trigger is SUID. The
-                         string contains user name part of the actual trigger
-                         definer.
-                       - NULL-string is returned if the trigger is non-SUID.
-                     Anyway, the caller is responsible to provide memory for
-                     storing LEX_STRING object.
-      definer_host - [out] after a call it points to 0-terminated string or
-                     contains the NULL-string:
-                       - 0-terminated string is returned if the trigger is
-                         SUID. The string contains host name part of the
-                         actual trigger definer.
-                       - NULL-string is returned if the trigger is non-SUID.
-                     Anyway, the caller is responsible to provide memory for
-                     storing LEX_STRING object.
+      stmt_query   - [OUT] after successful return, this string
contains
+                     well-formed
statement for creation this trigger.
 
   NOTE
     - Assumes that trigger name is fully qualified.
@@ -352,8 +317,7 @@ end:
     True  - error
 */
 bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
-                                         LEX_STRING *definer_user,
-                                         LEX_STRING *definer_host)
+                                         String *stmt_query)
 {
   LEX *lex= thd->lex;
   TABLE *table= tables->table;
@@ -361,6 +325,8 @@ bool Table_triggers_list::create_trigger
        trigname_path[FN_REFLEN];
   LEX_STRING dir, file, trigname_file;
   LEX_STRING *trg_def, *name;
+  LEX_STRING definer_user;
+  LEX_STRING definer_host;
   ulonglong *trg_sql_mode;
   char trg_definer_holder[USER_HOST_BUFF_SIZE];
   LEX_STRING *trg_definer;
@@ -416,9 +382,10 @@ bool Table_triggers_list::create_trigger
   */
   
   if (lex->definer &&
-      (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) ||
+      (strcmp(lex->definer->user_name.get_c_str(),
+              thd->security_ctx->priv_user) ||
        my_strcasecmp(system_charset_info,
-                     lex->definer->host.str,
+                     lex->definer->host_name.get_c_str(),
                      thd->security_ctx->priv_host)))
   {
     if (check_global_access(thd, SUPER_ACL))
@@ -508,20 +475,18 @@ bool Table_triggers_list::create_trigger
       definers_list.push_back(trg_definer, &table->mem_root))
     goto err_with_cleanup;
 
-  trg_def->str= thd->query;
-  trg_def->length= thd->query_length;
   *trg_sql_mode= thd->variables.sql_mode;
 
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
-  if (lex->definer && !is_acl_user(lex->definer->host.str,
-                                   lex->definer->user.str))
+  if (lex->definer && !is_acl_user(lex->definer->host_name.get_c_str(),
+                                   lex->definer->user_name.get_c_str()))
   {
     push_warning_printf(thd,
                         MYSQL_ERROR::WARN_LEVEL_NOTE,
                         ER_NO_SUCH_USER,
                         ER(ER_NO_SUCH_USER),
-                        lex->definer->user.str,
-                        lex->definer->host.str);
+                        lex->definer->user_name.get_c_str(),
+                        lex->definer->host_name.get_c_str());
   }
 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
 
@@ -529,27 +494,55 @@ bool Table_triggers_list::create_trigger
   {
     /* SUID trigger. */
 
-    *definer_user= lex->definer->user;
-    *definer_host= lex->definer->host;
+    definer_user= *lex->definer->user_name.get_str();
+    definer_host= *lex->definer->host_name.get_str();
 
     trg_definer->str= trg_definer_holder;
-    trg_definer->length= strxmov(trg_definer->str, definer_user->str, "@",
-                                 definer_host->str, NullS) - trg_definer->str;
+    trg_definer->length= strxmov(trg_definer->str, definer_user.str, "@",
+                                 definer_host.str, NullS) - trg_definer->str;
   }
   else
   {
     /* non-SUID trigger. */
 
-    definer_user->str= 0;
-    definer_user->length= 0;
+    definer_user.str= 0;
+    definer_user.length= 0;
 
-    definer_host->str= 0;
-    definer_host->length= 0;
+    definer_host.str= 0;
+    definer_host.length= 0;
 
     trg_definer->str= (char*) "";
     trg_definer->length= 0;
   }
 
+  /*
+    Create well-formed trigger definition query. Original query is not
+    appropriated, because definer-clause can be not truncated.
+  */
+
+  stmt_query->append(STRING_WITH_LEN("CREATE "));
+
+  if (trg_definer)
+  {
+    /*
+      Append definer-clause if the trigger is SUID (a usual trigger in
+      new MySQL versions).
+    */
+
+    append_definer(thd, stmt_query, &definer_user, &definer_host);
+  }
+
+  stmt_query->append(thd->lex->stmt_definition_begin,
+                     (char *) thd->lex->sphead->m_body_begin -
+                     thd->lex->stmt_definition_begin +
+                     thd->lex->sphead->m_body.length);
+
+  trg_def->str= stmt_query->c_ptr();
+  trg_def->length= stmt_query->length();
+
+  /* Create trigger definition file. */
+
+
   if (!sql_create_definition_file(&dir, &file, &triggers_file_type,
                                   (gptr)this, triggers_file_parameters, 0))
     return 0;
@@ -647,15 +640,19 @@ static bool save_trigger_file(Table_trig
 
   SYNOPSIS
     drop_trigger()
-      thd    - current thread context (including trigger definition in LEX)
-      tables - table list containing one open table for which trigger is
-               dropped.
+      thd         - current thread context
+                    (including trigger definition in LEX)
+      tables      - table list containing one open table for which trigger
+                    is dropped.
+      stmt_query  - [OUT] after successful return, this string
contains
+                    well-formed
statement for creation this trigger.
 
   RETURN VALUE
     False - success
     True  - error
 */
-bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
+bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables,
+                                       String *stmt_query)
 {
   LEX *lex= thd->lex;
   LEX_STRING *name;
@@ -665,6 +662,8 @@ bool Table_triggers_list::drop_trigger(T
   List_iterator<LEX_STRING>      it_definer(definers_list);
   char path[FN_REFLEN];
 
+  stmt_query->append(thd->query, thd->query_length);
+
   while ((name= it_name++))
   {
     it_def++;
@@ -974,6 +973,8 @@ bool Table_triggers_list::check_n_load(T
 
         if (!trg_definer->length)
         {
+          LEX_STRING empty_definer= { "", 0 };
+
           /*
             This trigger was created/imported from the previous version of
             MySQL, which does not support triggers definers. We should emit
@@ -990,7 +991,7 @@ bool Table_triggers_list::check_n_load(T
             schema.
           */
 
-          lex.sphead->set_definer("", 0);
+          lex.sphead->set_definer(thd, &empty_definer);
 
           /*
             Triggers without definer information are executed under the
@@ -1000,7 +1001,7 @@ bool Table_triggers_list::check_n_load(T
           lex.sphead->m_chistics->suid= SP_IS_NOT_SUID;
         }
         else
-          lex.sphead->set_definer(trg_definer->str, trg_definer->length);
+          lex.sphead->set_definer(thd, trg_definer);
 
         if (triggers->names_list.push_back(&lex.sphead->m_name,
                                            &table->mem_root))
@@ -1437,8 +1438,8 @@ bool Table_triggers_list::change_table_n
   }
   if (table.triggers)
   {
-    LEX_STRING_WITH_INIT old_table_name(old_table, strlen(old_table));
-    LEX_STRING_WITH_INIT new_table_name(new_table, strlen(new_table));
+    LEX_STRING old_table_name= { (char *) old_table, strlen(old_table) };
+    LEX_STRING new_table_name= { (char *) new_table, strlen(new_table) };
     /*
       Since triggers should be in the same schema as their subject tables
       moving table with them between two schemas raises too many questions.

--- 1.20/sql/sql_trigger.h	2006-07-28 20:03:16 +04:00
+++ 1.21/sql/sql_trigger.h	2006-07-28 20:03:16 +04:00
@@ -92,10 +92,8 @@ public:
   }
   ~Table_triggers_list();
 
-  bool create_trigger(THD *thd, TABLE_LIST *table,
-                      LEX_STRING *definer_user,
-                      LEX_STRING *definer_host);
-  bool drop_trigger(THD *thd, TABLE_LIST *table);
+  bool create_trigger(THD *thd, TABLE_LIST *table, String *stmt_query);
+  bool drop_trigger(THD *thd, TABLE_LIST *table, String *stmt_query);
   bool process_triggers(THD *thd, trg_event_type event,
                         trg_action_time_type time_type,
                         bool old_row_is_record1);

--- 1.158/sql/set_var.cc	2006-07-28 20:03:16 +04:00
+++ 1.159/sql/set_var.cc	2006-07-28 20:03:16 +04:00
@@ -3292,25 +3292,42 @@ int set_var_user::update(THD *thd)
   Functions to handle SET PASSWORD
 *****************************************************************************/
 
+set_var_password::set_var_password(THD *thd,
+                                   LEX_STRING *user_name_arg,
+                                   LEX_STRING *host_name_arg,
+                                   char *password_arg)
+{
+  LEX_STRING password_str= { password_arg, strlen(password_arg) };
+
+  user.set(thd, user_name_arg, host_name_arg, &password_str);
+}
+
 int set_var_password::check(THD *thd)
 {
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
-  if (!user->host.str)
+  if (!user.host_name.get_c_str())
   {
+    LEX_STRING host_name_str;
+
     if (*thd->security_ctx->priv_host != 0)
     {
-      user->host.str= (char *) thd->security_ctx->priv_host;
-      user->host.length= strlen(thd->security_ctx->priv_host);
+      host_name_str.str= thd->security_ctx->priv_host;
+      host_name_str.length= strlen(host_name_str.str);
     }
     else
     {
-      user->host.str= (char *)"%";
-      user->host.length= 1;
+      host_name_str.str= (char *) "%";
+      host_name_str.length= 1;
     }
+
+    user.host_name.set(thd, &host_name_str);
   }
   /* Returns 1 as the function sends error to client */
-  return check_change_password(thd, user->host.str, user->user.str,
-                               password, strlen(password)) ? 1 : 0;
+  return check_change_password(thd,
+                               user.host_name.get_c_str(),
+                               user.user_name.get_c_str(),
+                               user.password.str,
+                               user.password.length) ? 1 : 0;
 #else
   return 0;
 #endif
@@ -3320,8 +3337,10 @@ int set_var_password::update(THD *thd)
 {
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
   /* Returns 1 as the function sends error to client */
-  return change_password(thd, user->host.str, user->user.str, password) ?
-	  1 : 0;
+  return change_password(thd,
+                         user.host_name.get_c_str(),
+                         user.user_name.get_c_str(),
+                         user.password.str) ?  1 : 0;
 #else
   return 0;
 #endif

--- 1.78/sql/set_var.h	2006-07-28 20:03:16 +04:00
+++ 1.79/sql/set_var.h	2006-07-28 20:03:16 +04:00
@@ -913,12 +913,15 @@ public:
 
 class set_var_password: public set_var_base
 {
-  LEX_USER *user;
-  char *password;
+  Lex_user user;
+
+public:
+  set_var_password(THD *thd,
+                   LEX_STRING *user_name_arg,
+                   LEX_STRING *host_name_arg,
+                   char *password_arg);
+
 public:
-  set_var_password(LEX_USER *user_arg,char *password_arg)
-    :user(user_arg), password(password_arg)
-  {}
   int check(THD *thd);
   int update(THD *thd);
 };

--- 1.204/mysql-test/r/sp.result	2006-07-28 20:03:16 +04:00
+++ 1.205/mysql-test/r/sp.result	2006-07-28 20:03:16 +04:00
@@ -5222,4 +5222,27 @@ CHARSET(p3)	COLLATION(p3)
 greek	greek_general_ci
 use test|
 DROP DATABASE mysqltest1|
+DROP PROCEDURE IF EXISTS bug16899_p1|
+DROP FUNCTION IF EXISTS bug16899_f1|
+CREATE DEFINER=1234567890abcdefGHIKL@localhost PROCEDURE bug16899_p1()
+BEGIN
+SET @a = 1;
+END|
+Warnings:
+Note	1466	The user name has been truncated to 16 symbols
+Note	1449	There is no '1234567890abcdef'@'localhost' registered
+CREATE
DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
+FUNCTION bug16899_f1() RETURNS INT
+BEGIN
+RETURN 1;
+END|
+Warnings:
+Note	1467	The host name has been truncated to 60 symbols
+Note	1449	There is no
'some_user_name'@'1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij'
registered
+CALL bug16899_p1()|
+ERROR HY000: There is no '1234567890abcdef'@'localhost' registered
+SELECT bug16899_f1()|
+ERROR HY000: There is no
'some_user_name'@'1234567890abcdefghij1234567890abcdefghij1234567890abcdefghij'
registered
+DROP PROCEDURE bug16899_p1|
+DROP FUNCTION bug16899_f1|
 drop table t1,t2;

--- 1.192/mysql-test/t/sp.test	2006-07-28 20:03:16 +04:00
+++ 1.193/mysql-test/t/sp.test	2006-07-28 20:03:16 +04:00
@@ -6148,6 +6148,42 @@ use test|
 DROP DATABASE mysqltest1|
 
 #
+# Test for BUG#16899: Possible buffer overflow in handling of DEFINER-clause.
+#
+
+# Prepare.
+
+--disable_warnings
+DROP PROCEDURE IF EXISTS bug16899_p1|
+DROP FUNCTION IF EXISTS bug16899_f1|
+--enable_warnings
+
+CREATE DEFINER=1234567890abcdefGHIKL@localhost PROCEDURE bug16899_p1()
+BEGIN
+  SET @a = 1;
+END|
+
+CREATE
DEFINER=some_user_name@1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY
+  FUNCTION bug16899_f1() RETURNS INT
+BEGIN
+  RETURN 1;
+END|
+
+# Test.
+
+--error ER_NO_SUCH_USER
+CALL bug16899_p1()|
+
+--error ER_NO_SUCH_USER
+SELECT bug16899_f1()|
+
+# Cleanup.
+
+DROP PROCEDURE bug16899_p1|
+DROP FUNCTION bug16899_f1|
+
+
+#
 # BUG#NNNN: New bug synopsis
 #
 #--disable_warnings

--- 1.115/sql/sp.cc	2006-07-28 20:03:16 +04:00
+++ 1.116/sql/sp.cc	2006-07-28 20:03:16 +04:00
@@ -37,7 +37,7 @@ static int
 db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
                 ulong sql_mode, const char *params, const char *returns,
                 const char *body, st_sp_chistics &chistics,
-                const char *definer, longlong created, longlong modified);
+                const LEX_STRING *definer, longlong created, longlong modified);
 
 /*
  *
@@ -272,7 +272,7 @@ db_find_routine(THD *thd, int type, sp_n
   TABLE *table;
   const char *params, *returns, *body;
   int ret;
-  const char *definer;
+  LEX_STRING definer;
   longlong created;
   longlong modified;
   st_sp_chistics chistics;
@@ -362,8 +362,8 @@ db_find_routine(THD *thd, int type, sp_n
   }
 
   // Get additional information
-  if ((definer= get_field(thd->mem_root,
-			  table->field[MYSQL_PROC_FIELD_DEFINER])) == NULL)
+  if (get_field(thd->mem_root, table->field[MYSQL_PROC_FIELD_DEFINER],
+                &definer) || definer.length == 0)
   {
     ret= SP_GET_FIELD_FAILED;
     goto done;
@@ -387,7 +387,7 @@ db_find_routine(THD *thd, int type, sp_n
 
   ret= db_load_routine(thd, type, name, sphp,
                        sql_mode, params, returns, body, chistics,
-                       definer, created, modified);
+                       &definer, created, modified);
                        
  done:
   if (table)
@@ -400,7 +400,7 @@ static int
 db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
                 ulong sql_mode, const char *params, const char *returns,
                 const char *body, st_sp_chistics &chistics,
-                const char *definer, longlong created, longlong modified)
+                const LEX_STRING *definer, longlong created, longlong modified)
 {
   LEX *old_lex= thd->lex, newlex;
   String defstr;
@@ -410,15 +410,13 @@ db_load_routine(THD *thd, int type, sp_n
   ulong old_sql_mode= thd->variables.sql_mode;
   ha_rows old_select_limit= thd->variables.select_limit;
   sp_rcontext *old_spcont= thd->spcont;
-  
+
   char definer_user_name_holder[USERNAME_LENGTH + 1];
-  LEX_STRING_WITH_INIT definer_user_name(definer_user_name_holder,
-                                         USERNAME_LENGTH);
+  LEX_STRING definer_user_name= { definer_user_name_holder, USERNAME_LENGTH };
 
   char definer_host_name_holder[HOSTNAME_LENGTH + 1];
-  LEX_STRING_WITH_INIT definer_host_name(definer_host_name_holder,
-                                         HOSTNAME_LENGTH);
-  
+  LEX_STRING definer_host_name= { definer_host_name_holder, HOSTNAME_LENGTH };
+
   int ret;
 
   thd->variables.sql_mode= sql_mode;
@@ -427,9 +425,20 @@ db_load_routine(THD *thd, int type, sp_n
   thd->lex= &newlex;
   newlex.current_select= NULL;
 
-  parse_user(definer, strlen(definer),
-             definer_user_name.str, &definer_user_name.length,
-             definer_host_name.str, &definer_host_name.length);
+  /*
+    Split the definer into user and host names.
+
+    If user name (host name) is longer than USERNAME_LENGTH (HOSTNAME_LENGTH),
+    it will be truncated and corresponding warning will be emitted. This
+    truncation can occur, when we are loading stored routine created in the
+    MySQL before 5.0.23 -- there was no checkings for length. As of 5.0.23
+    such checkings are before creating the stored routine, so we will never
+    truncate here.
+  */
+
+  parse_user(definer, &definer_user_name, &definer_host_name,
+             on_user_name_truncated,
+             on_host_name_truncated);
 
   defstr.set_charset(system_charset_info);
 
@@ -531,8 +540,9 @@ db_create_routine(THD *thd, int type, sp
     restore_record(table, s->default_values); // Get default values for fields
 
     /* NOTE: all needed privilege checks have been already done. */
-    strxmov(definer, thd->lex->definer->user.str, "@",
-            thd->lex->definer->host.str, NullS);
+    strxmov(definer,
+            thd->lex->definer->user_name.get_c_str(), "@",
+            thd->lex->definer->host_name.get_c_str(), NullS);
 
     if (table->s->fields != MYSQL_PROC_FIELD_COUNT)
     {
@@ -631,8 +641,9 @@ db_create_routine(THD *thd, int type, sp
       String log_query;
       log_query.set_charset(system_charset_info);
       log_query.append(STRING_WITH_LEN("CREATE "));
-      append_definer(thd, &log_query, &thd->lex->definer->user,
-                     &thd->lex->definer->host);
+      append_definer(thd, &log_query,
+                     thd->lex->definer->user_name.get_str(),
+                     thd->lex->definer->host_name.get_str());
       log_query.append(thd->lex->stmt_definition_begin,
                        (char *)sp->m_body_begin -
                        thd->lex->stmt_definition_begin +
@@ -983,7 +994,8 @@ sp_find_routine(THD *thd, int type, sp_n
     ulong level;
     sp_head *new_sp;
     const char *returns= "";
-    char definer[USER_HOST_BUFF_SIZE];
+    char definer_holder[USER_HOST_BUFF_SIZE];
+    LEX_STRING definer= { definer_holder, 0 };
 
     /*
       String buffer for RETURNS data type must have system charset;
@@ -1013,8 +1025,9 @@ sp_find_routine(THD *thd, int type, sp_n
       DBUG_RETURN(0);
     }
 
-    strxmov(definer, sp->m_definer_user.str, "@",
-            sp->m_definer_host.str, NullS);
+    definer.length= strxmov(definer.str, sp->m_definer_user.str, "@",
+                            sp->m_definer_host.str, NullS) - definer.str;
+
     if (type == TYPE_ENUM_FUNCTION)
     {
       sp_returns_type(thd, retstr, sp);
@@ -1022,7 +1035,7 @@ sp_find_routine(THD *thd, int type, sp_n
     }
     if (db_load_routine(thd, type, name, &new_sp,
                         sp->m_sql_mode, sp->m_params.str, returns,
-                        sp->m_body.str, *sp->m_chistics, definer,
+                        sp->m_body.str, *sp->m_chistics, &definer,
                         sp->m_created, sp->m_modified) == SP_OK)
     {
       sp->m_last_cached_sp->m_next_cached_sp= new_sp;
@@ -1823,6 +1836,7 @@ create_string(THD *thd, String *buf,
     buf->append('\n');
   }
   buf->append(body, bodylen);
+
   return TRUE;
 }
 

--- 1.221/sql/sp_head.cc	2006-07-28 20:03:16 +04:00
+++ 1.222/sql/sp_head.cc	2006-07-28 20:03:16 +04:00
@@ -1949,16 +1949,28 @@ sp_head::set_info(longlong created, long
 
 
 void
-sp_head::set_definer(const char *definer, uint definerlen)
+sp_head::set_definer(THD *thd, const LEX_STRING *definer)
 {
   char user_name_holder[USERNAME_LENGTH + 1];
-  LEX_STRING_WITH_INIT user_name(user_name_holder, USERNAME_LENGTH);
+  LEX_STRING user_name= { user_name_holder, USERNAME_LENGTH };
 
   char host_name_holder[HOSTNAME_LENGTH + 1];
-  LEX_STRING_WITH_INIT host_name(host_name_holder, HOSTNAME_LENGTH);
+  LEX_STRING host_name= { host_name_holder, HOSTNAME_LENGTH };
 
-  parse_user(definer, definerlen, user_name.str, &user_name.length,
-             host_name.str, &host_name.length);
+  /*
+    Split the definer into user and host names.
+
+    If user name (host name) is longer than USERNAME_LENGTH (HOSTNAME_LENGTH),
+    it will be truncated and corresponding warning will be emitted. This
+    truncation can occur, when we are loading stored routine or trigger
+    created in the MySQL before 5.0.23 -- there was no checkings for length.
+    As of 5.0.23 such checkings are before creating the stored routine, so we
+    will never truncate here.
+  */
+
+  parse_user(definer, &user_name, &host_name,
+             on_user_name_truncated,
+             on_host_name_truncated);
 
   set_definer(&user_name, &host_name);
 }

--- 1.87/sql/sp_head.h	2006-07-28 20:03:16 +04:00
+++ 1.88/sql/sp_head.h	2006-07-28 20:03:16 +04:00
@@ -293,7 +293,7 @@ public:
   void set_info(longlong created, longlong modified,
 		st_sp_chistics *chistics, ulong sql_mode);
 
-  void set_definer(const char *definer, uint definerlen);
+  void set_definer(THD *thd, const LEX_STRING *definer);
   void set_definer(const LEX_STRING *user_name, const LEX_STRING *host_name);
 
   void reset_thd_mem_root(THD *thd);
Thread
bk commit into 5.0 tree (anozdrin:1.2244) BUG#16899Alexander Nozdrin28 Jul