List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:July 29 2006 4:12pm
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-29 18:11:53+04:00, anozdrin@booka. +35 -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-29 12:38:33+04:00, anozdrin@booka. +2 -0
    BitKeeper file /mnt/raid/alik/MySQL/devel/5.0-rt-bug16899/BitKeeper/etc/collapsed

  BitKeeper/etc/collapsed@stripped, 2006-07-29 12:38:33+04:00, anozdrin@booka. +0 -0

  client/mysqldump.c@stripped, 2006-07-29 18:11:48+04:00, anozdrin@booka. +46 -18
    Updated parse_user().

  include/m_string.h@stripped, 2006-07-29 18:11:48+04:00, anozdrin@booka. +18 -0
    Moved LEX_STRING out of server directory.

  include/my_user.h@stripped, 2006-07-29 18:11:48+04:00, anozdrin@booka. +13 -3
    Updated parse_user().

  mysql-test/r/sp.result@stripped, 2006-07-29 18:11:48+04:00, anozdrin@booka. +23 -0
    Updated result file.

  mysql-test/r/trigger.result@stripped, 2006-07-29 18:11:48+04:00, anozdrin@booka. +21 -0
    Updated result file.

  mysql-test/r/view.result@stripped, 2006-07-29 18:11:48+04:00, anozdrin@booka. +27 -0
    Updated result file.

  mysql-test/t/sp.test@stripped, 2006-07-29 18:11:48+04:00, anozdrin@booka. +36 -0
    Added test for BUG#16899.

  mysql-test/t/trigger.test@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +36 -0
    Updated result file.

  mysql-test/t/view.test@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +32 -0
    Updated result file.

  sql-common/my_user.c@stripped, 2006-07-29 18:11:50+04:00, anozdrin@booka. +54 -20
    parse_user() impl.

  sql/mysql_priv.h@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +4 -4
    Added convenient get_field() function.

  sql/set_var.cc@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +28 -9
    Updated set_var_password() to work with modified LEX_USER.

  sql/set_var.h@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +8 -5
    Updated set_var_password() to work with modified LEX_USER.

  sql/share/errmsg.txt@stripped, 2006-07-29 18:11:50+04:00, anozdrin@booka. +4 -0
    Aded new error messages.

  sql/sp.cc@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +37 -23
    Updated.

  sql/sp_head.cc@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +17 -5
    Use new parse_user().

  sql/sp_head.h@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +1 -1
    Use LEX_STRING.

  sql/spatial.cc@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +4 -1
    Get rid of LEX_STRING_WITH_INIT.

  sql/spatial.h@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +1 -1
    Get rid of LEX_STRING_WITH_INIT.

  sql/sql_acl.cc@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +273 -183
    Reflect LEX_USER changes.

  sql/sql_acl.h@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +8 -8
    LEX_USER -> Lex_user

  sql/sql_class.cc@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +27 -0
    Provide server-wide callbacks for parse_user().

  sql/sql_class.h@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +11 -0
    Provide server-wide callbacks for parse_user().

  sql/sql_lex.h@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +3 -3
    LEX_USER -> Lex_user

  sql/sql_parse.cc@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +54 -80
    1. Reflect LEX_USER changes.
    2. Eleminate create_definer().

  sql/sql_show.cc@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +13 -6
    Reflect LEX_USER changes.

  sql/sql_string.h@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +0 -2
    Get rid of STRING_WITH_LEN.

  sql/sql_trigger.cc@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +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-29 18:11:49+04:00, anozdrin@booka. +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-29 18:11:49+04:00, anozdrin@booka. +16 -16
    Reflect LEX_USER changes.

  sql/sql_yacc.yy@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +86 -74
    Reflect LEX_USER changes.

  sql/structs.h@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +0 -21
    LEX_USER changed.

  sql/table.cc@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +137 -19
    Reflect LEX_USER changes.

  sql/table.h@stripped, 2006-07-29 18:11:49+04:00, anozdrin@booka. +181 -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:	booka.
# Root:	/home/alik/MySQL/devel/5.0-rt-bug16899

--- 1.232/client/mysqldump.c	2006-07-29 18:12:00 +04:00
+++ 1.233/client/mysqldump.c	2006-07-29 18:12:00 +04:00
@@ -1893,6 +1893,24 @@ continue_xml:
 } /* get_table_structure */
 
 
+static void mysqldump_on_user_name_truncated(const PARSE_USER_CB_CTX *ctx)
+{
+  fprintf(stderr,
+          "Warning: user name '%s' has been truncated to %d symbols\n",
+          (const char *) ctx->original_name,
+          (int) USERNAME_LENGTH);
+}
+
+
+static void mysqldump_on_host_name_truncated(const PARSE_USER_CB_CTX *ctx)
+{
+  fprintf(stderr,
+          "Warning: host name '%s' has been truncated to %d symbols\n",
+          (const char *) ctx->original_name,
+          (int) HOSTNAME_LENGTH);
+}
+
+
 /*
 
   dump_triggers_for_table
@@ -1949,20 +1967,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,
+                 mysqldump_on_user_name_truncated,
+                 mysqldump_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 +3488,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,
+                 mysqldump_on_user_name_truncated,
+                 mysqldump_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-29 18:12:00 +04:00
+++ 1.38/include/m_string.h	2006-07-29 18:12:00 +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-29 18:12:00 +04:00
+++ 1.400/sql/mysql_priv.h	2006-07-29 18:12:00 +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-29 18:12:00 +04:00
+++ 1.199/sql/sql_acl.cc	2006-07-29 18:12:00 +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,7 +1801,9 @@ 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)
@@ -1806,9 +1814,11 @@ static int replace_user_table(THD *thd, 
     }
     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 +1941,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 +1951,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 +1970,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 +1988,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 +2012,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 +2065,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 +2347,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 +2358,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 +2403,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 +2538,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 +2557,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 +2566,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 +2591,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 +2663,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 +2686,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 +2719,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 +2802,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;
@@ -2899,15 +2941,8 @@ bool mysql_table_grant(THD *thd, TABLE_L
     {
       result= TRUE;
       continue;
-    }  
-    if (Str->host.length > HOSTNAME_LENGTH ||
-	Str->user.length > USERNAME_LENGTH)
-    {
-      my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
-                 MYF(0));
-      result= TRUE;
-      continue;
     }
+
     /* Create user if needed */
     error=replace_user_table(thd, tables[0].table, *Str,
 			     0, revoke_grant, create_new_users,
@@ -2927,19 +2962,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 +3068,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;
@@ -3111,16 +3148,8 @@ bool mysql_routine_grant(THD *thd, TABLE
     {
       result= TRUE;
       continue;
-    }  
-    if (Str->host.length > HOSTNAME_LENGTH ||
-	Str->user.length > USERNAME_LENGTH)
-    {
-      if (!no_error)
-	my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
-                   MYF(0));
-      result= TRUE;
-      continue;
     }
+
     /* Create user if needed */
     error=replace_user_table(thd, tables[0].table, *Str,
 			     0, revoke_grant, create_new_users,
@@ -3135,20 +3164,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 +3208,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];
@@ -3245,15 +3277,8 @@ bool mysql_grant(THD *thd, const char *d
     {
       result= TRUE;
       continue;
-    }  
-    if (Str->host.length > HOSTNAME_LENGTH ||
-	Str->user.length > USERNAME_LENGTH)
-    {
-      my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
-                 MYF(0));
-      result= -1;
-      continue;
     }
+
     if (replace_user_table(thd, tables[0].table, *Str,
                            (!db ? rights : 0), revoke_grant, create_new_users,
                            test(thd->variables.sql_mode &
@@ -4114,7 +4139,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 +4151,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,25 +4169,27 @@ 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.is_truncated() ||
+      lex_user->user_name.is_truncated())
   {
-    my_message(ER_GRANT_WRONG_HOST_OR_USER, ER(ER_GRANT_WRONG_HOST_OR_USER),
-               MYF(0));
+    my_message(ER_GRANT_WRONG_HOST_OR_USER,
+               ER(ER_GRANT_WRONG_HOST_OR_USER), MYF(0));
     DBUG_RETURN(TRUE);
   }
 
   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 +4197,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 +4236,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 +4328,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 +4361,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 +4394,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 +4473,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 +4516,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 +4534,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 +4576,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 +4740,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 +4749,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 +4802,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 +4830,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 +4948,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 +4960,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 +4989,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 +5032,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 +5066,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 +5124,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 +5222,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 +5247,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 +5312,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 +5368,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 +5438,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 +5452,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 +5496,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 +5529,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 +5577,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 +5647,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 +5707,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);
 
-  VOID(pthread_mutex_lock(&acl_cache->lock));
+    combo->user_name.set(thd, &user_name_str);
+  }
 
-  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;
+  {
+    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
+    };
 
-  VOID(pthread_mutex_unlock(&acl_cache->lock));
-  DBUG_RETURN(TRUE);
+    VOID(pthread_mutex_lock(&acl_cache->lock));
 
- found_acl:
-  VOID(pthread_mutex_unlock(&acl_cache->lock));
+    for (const char *var= host_name_variants[0]; var; ++var)
+    {
+      if ((au= find_acl_user(var, user_name, FALSE)))
+      {
+        host_name= var;
+        break;
+      }
+    }
+
+    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 +5770,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 +5791,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 +5802,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 +5813,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-29 18:12:00 +04:00
+++ 1.51/sql/sql_acl.h	2006-07-29 18:12:00 +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-29 18:12:00 +04:00
+++ 1.240/sql/sql_class.cc	2006-07-29 18:12:00 +04:00
@@ -2199,3 +2199,30 @@ 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 mysqld_on_user_name_truncated(const PARSE_USER_CB_CTX *ctx)
+{
+  push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+                      ER_USER_NAME_TRUNCATED,
+                      ER(ER_USER_NAME_TRUNCATED),
+                      (const char *) ctx->original_name,
+                      USERNAME_LENGTH);
+}
+
+
+void mysqld_on_host_name_truncated(const PARSE_USER_CB_CTX *ctx)
+{
+  push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+                      ER_HOST_NAME_TRUNCATED,
+                      ER(ER_HOST_NAME_TRUNCATED),
+                      (const char *) ctx->original_name,
+                      HOSTNAME_LENGTH);
+}
+
+C_MODE_END

--- 1.293/sql/sql_class.h	2006-07-29 18:12:00 +04:00
+++ 1.294/sql/sql_class.h	2006-07-29 18:12:00 +04:00
@@ -21,6 +21,8 @@
 #pragma interface			/* gcc class implementation */
 #endif
 
+#include "my_user.h"
+
 // TODO: create log.h and move all the log header stuff there
 
 class Query_log_event;
@@ -2154,3 +2156,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 mysqld_on_user_name_truncated(const PARSE_USER_CB_CTX *ctx);
+extern void mysqld_on_host_name_truncated(const PARSE_USER_CB_CTX *ctx);
+
+C_MODE_END

--- 1.223/sql/sql_lex.h	2006-07-29 18:12:00 +04:00
+++ 1.224/sql/sql_lex.h	2006-07-29 18:12:00 +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-29 18:12:00 +04:00
+++ 1.562/sql/sql_parse.cc	2006-07-29 18:12:00 +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,20 +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.
-    On error, return 0.
+    Lex_user, which contains user information.
+    On error, return NULL.
 */
 
-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))))
-    {
-      my_error(ER_OUTOFMEMORY, MYF(0), sizeof(LEX_USER));
-      return 0;
-    }
+    if (!(curr_user= (Lex_user*) thd->alloc(sizeof(Lex_user))))
+      return NULL;
+
     get_default_definer(thd, curr_user);
     return curr_user;
   }

--- 1.324/sql/sql_show.cc	2006-07-29 18:12:00 +04:00
+++ 1.325/sql/sql_show.cc	2006-07-29 18:12:00 +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-29 18:12:00 +04:00
+++ 1.61/sql/sql_string.h	2006-07-29 18:12:00 +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-29 18:12:00 +04:00
+++ 1.477/sql/sql_yacc.yy	2006-07-29 18:12:00 +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))))
-              YYABORT;
-            bzero(curr_user, sizeof(st_lex_user));
+	    Lex_user *curr_user;
+	    if (!(curr_user= (Lex_user*) lex->thd->alloc(sizeof(Lex_user))))
+	      YYABORT;
+	    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))))
-	      YYABORT;
-	    $$->user = $1; $$->host=$3;
-	  }
+	{
+	  if (!($$=(Lex_user*) YYTHD->alloc(sizeof(Lex_user))))
+	    YYABORT;
+
+	  $$->set(YYTHD, &$1, &$3, NULL);
+	}
 	| CURRENT_USER optional_braces
 	{
-          if (!($$=(LEX_USER*) YYTHD->alloc(sizeof(st_lex_user))))
-            YYABORT;
-          /* 
-            empty LEX_USER means current_user and 
-            will be handled in the  get_current_user() function
-            later
-          */
-          bzero($$, sizeof(LEX_USER));
+	  if (!($$=(Lex_user*) YYTHD->alloc(sizeof(Lex_user))))
+	    YYABORT;
+	  /*
+	    empty Lex_user means current_user and
+	    will be handled in the  get_current_user() function
+	    later
+	  */
+	  bzero($$, sizeof(Lex_user));
 	};
 
 /* Keyword that we allow for identifiers (except SP labels) */
@@ -8018,30 +8018,33 @@ option_value:
 	  lex->var_list.push_back(new set_var_collation_client($3,$3,$3));
 	}
 	| PASSWORD equal text_or_password
-	  {
-	    THD *thd=YYTHD;
-	    LEX_USER *user;
-	    LEX *lex= Lex;	    
-            sp_pcontext *spc= lex->spcont;
-	    LEX_STRING pw;
+	{
+	  THD *thd=YYTHD;
+	  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;
 
-	    pw.str= (char *)"password";
-	    pw.length= 8;
-	    if (spc && spc->find_variable(&pw))
-	    {
-              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));
-	  }
-	| PASSWORD FOR_SYM user equal text_or_password
+	  pw.str= (char *)"password";
+	  pw.length= 8;
+	  if (spc && spc->find_variable(&pw))
 	  {
-	    Lex->var_list.push_back(new set_var_password($3,$5));
+	    my_error(ER_SP_BAD_VAR_SHADOW, MYF(0), pw.str);
+	    YYABORT;
 	  }
+	  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(YYTHD,
+	                         $3->user_name.get_str(),
+	                         $3->host_name.get_str(),
+	                         $5));
+	}
 	;
 
 internal_variable_name:
@@ -8569,33 +8572,40 @@ grant_list:
 grant_user:
 	user IDENTIFIED_SYM BY TEXT_STRING
 	{
-	   $$=$1; $1->password=$4;
-	   if ($4.length)
-	   {
-             if (YYTHD->variables.old_passwords)
-             {
-               char *buff= 
-                 (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
-               if (buff)
-                 make_scrambled_password_323(buff, $4.str);
-               $1->password.str= buff;
-               $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
-             }
-             else
-             {
-               char *buff= 
-                 (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
-               if (buff)
-                 make_scrambled_password(buff, $4.str);
-               $1->password.str= buff;
-               $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
-             }
+	  $$=$1;
+	  $1->password= $4;
+	  if ($4.length)
+	  {
+	    if (YYTHD->variables.old_passwords)
+	    {
+	      char *buff=
+	        (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH_323+1);
+	      if (buff)
+	        make_scrambled_password_323(buff, $4.str);
+	      $1->password.str= buff;
+	      $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
+	    }
+	    else
+	    {
+	      char *buff=
+	        (char *) YYTHD->alloc(SCRAMBLED_PASSWORD_CHAR_LENGTH+1);
+	      if (buff)
+	        make_scrambled_password(buff, $4.str);
+	      $1->password.str= buff;
+	      $1->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
+	    }
 	  }
 	}
 	| 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,17 +8964,19 @@ 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
 	{
-          if (! (YYTHD->lex->definer= create_default_definer(YYTHD)))
-            YYABORT;
+	  if (! (YYTHD->lex->definer= create_default_definer(YYTHD)))
+	    YYABORT;
 	}
 	| DEFINER_SYM EQ ident_or_text '@' ident_or_text
 	{
-          if (!(YYTHD->lex->definer= create_definer(YYTHD, &$3, &$5)))
-            YYABORT;
+	  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-29 18:12:00 +04:00
+++ 1.56/sql/structs.h	2006-07-29 18:12:00 +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-29 18:12:00 +04:00
+++ 1.230/sql/table.cc	2006-07-29 18:12:00 +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,86 @@ void st_table_list::reinit_before_use(TH
 template class List<String>;
 template class List_iterator<String>;
 #endif
+
+
+/**************************************************************************
+  User_name implementation.
+**************************************************************************/
+
+void User_name::set(THD *thd, LEX_STRING *user_name)
+{
+  if (!user_name)
+  {
+    reset();
+    return;
+  }
+
+  if (user_name->length > USERNAME_LENGTH)
+  {
+    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+                        ER_USER_NAME_TRUNCATED,
+                        ER(ER_USER_NAME_TRUNCATED),
+                        (const char *) user_name->str,
+                        USERNAME_LENGTH);
+
+    user_name->str[USERNAME_LENGTH]= '\0';
+    user_name->length= USERNAME_LENGTH;
+
+    truncated= TRUE;
+  }
+  else
+    truncated= FALSE;
+
+  value= *user_name;
+}
+
+
+/**************************************************************************
+  Host_name implementation.
+**************************************************************************/
+
+void Host_name::set(THD *thd, LEX_STRING *host_name)
+{
+  if (!host_name)
+  {
+    reset();
+    return;
+  }
+
+  if (host_name->length > HOSTNAME_LENGTH)
+  {
+    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+                        ER_HOST_NAME_TRUNCATED,
+                        ER(ER_HOST_NAME_TRUNCATED),
+                        (const char *) host_name->str,
+                        HOSTNAME_LENGTH);
+
+    host_name->str[HOSTNAME_LENGTH]= '\0';
+    host_name->length= HOSTNAME_LENGTH;
+
+    truncated= TRUE;
+  }
+  else
+    truncated= FALSE;
+
+  value= *host_name;
+}
+
+
+/**************************************************************************
+  Lex_user implementation.
+**************************************************************************/
+
+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-29 18:12:00 +04:00
+++ 1.132/sql/table.h	2006-07-29 18:12:00 +04:00
@@ -24,6 +24,186 @@ class st_select_lex;
 class COND_EQUAL;
 class Security_context;
 
+
+/**************************************************************************
+  User_name declaration.
+**************************************************************************/
+
+class User_name
+{
+public:
+  inline User_name();
+
+public:
+  void set(THD *thd, LEX_STRING *user_name);
+
+  inline LEX_STRING *get_str();
+  inline char *get_c_str();
+  inline const char *get_c_str() const;
+  inline uint get_length() const;
+  inline bool is_truncated() const;
+
+  inline void reset();
+
+private:
+  LEX_STRING value;
+  bool truncated;
+};
+
+
+/**************************************************************************
+  User_name inline implementation.
+**************************************************************************/
+
+inline User_name::User_name()
+{
+  reset();
+}
+
+inline LEX_STRING *User_name::get_str()
+{
+  return &value;
+}
+
+inline char *User_name::get_c_str()
+{
+  return value.str;
+}
+
+inline const char *User_name::get_c_str() const
+{
+  return value.str;
+}
+
+inline uint User_name::get_length() const
+{
+  return value.length;
+}
+
+inline bool User_name::is_truncated() const
+{
+  return truncated;
+}
+
+inline void User_name::reset()
+{
+  value.str= NULL;
+  value.length= 0;
+
+  truncated= FALSE;
+}
+
+
+/**************************************************************************
+  Host_name declaration.
+**************************************************************************/
+
+class Host_name
+{
+public:
+  inline Host_name();
+
+public:
+  void set(THD *thd, LEX_STRING *host_name);
+
+  inline LEX_STRING *get_str();
+  inline char *get_c_str();
+  inline const char *get_c_str() const;
+  inline uint get_length() const;
+  inline bool is_truncated() const;
+
+  inline void reset();
+
+private:
+  LEX_STRING value;
+  bool truncated;
+};
+
+
+/**************************************************************************
+  Host_name inline implementation.
+**************************************************************************/
+
+inline Host_name::Host_name()
+{
+  reset();
+}
+
+inline LEX_STRING *Host_name::get_str()
+{
+  return &value;
+}
+
+inline char *Host_name::get_c_str()
+{
+  return value.str;
+}
+
+inline const char *Host_name::get_c_str() const
+{
+  return value.str;
+}
+
+inline uint Host_name::get_length() const
+{
+  return value.length;
+}
+
+inline bool Host_name::is_truncated() const
+{
+  return truncated;
+}
+
+inline void Host_name::reset()
+{
+  value.str= NULL;
+  value.length= 0;
+
+  truncated= FALSE;
+}
+
+
+/**************************************************************************
+  Lex_user declaration.
+**************************************************************************/
+
+class Lex_user
+{
+public:
+  inline 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();
+
+public:
+  User_name user_name;
+  Host_name host_name;
+
+  LEX_STRING password;
+};
+
+
+/**************************************************************************
+  Lex_user inline implementation.
+**************************************************************************/
+
+inline Lex_user::Lex_user()
+{
+  reset_password();
+}
+
+inline void Lex_user::reset_password()
+{
+  password.str= NULL;
+  password.length= 0;
+}
+
+
 /* Order clause list element */
 
 typedef struct st_order {
@@ -578,7 +758,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-29 18:12:00 +04:00
+++ 1.66/sql/share/errmsg.txt	2006-07-29 18:12:00 +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 "User name '%s' has been truncated to %d symbols"
+ER_HOST_NAME_TRUNCATED
+				eng "Host name '%s' has been truncated to %d symbols"
--- New file ---
+++ BitKeeper/etc/collapsed	06/07/29 12:38:33
44c793b7N8P7mznmNrhnNJOzRGevvA
44ca353dafuBX_DtdKwAKcBQoxumbA


--- 1.1/include/my_user.h	2006-07-29 18:12:00 +04:00
+++ 1.2/include/my_user.h	2006-07-29 18:12:00 +04:00
@@ -23,12 +23,22 @@
 #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 struct
+{
+  const char *original_name;
+} PARSE_USER_CB_CTX;
+
+typedef void (*parse_user_cb)(const PARSE_USER_CB_CTX *);
+
+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-29 18:12:00 +04:00
+++ 1.2/sql-common/my_user.c	2006-07-29 18:12:00 +04:00
@@ -14,6 +14,8 @@
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  US