List:Commits« Previous MessageNext Message »
From:konstantin Date:June 26 2006 8:53pm
Subject:bk commit into 5.0 tree (konstantin:1.2200)
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of kostja. When kostja does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet
  1.2200 06/06/27 00:52:56 konstantin@stripped +15 -0
  Merge bk-internal.mysql.com:/home/bk/mysql-5.0-runtime
  into  mysql.com:/opt/local/work/mysql-5.0-17199

  mysql-test/t/sp.test
    1.190 06/06/27 00:52:52 konstantin@stripped +0 -0
    SCCS merged

  mysql-test/r/sp.result
    1.202 06/06/27 00:52:52 konstantin@stripped +0 -0
    SCCS merged

  sql/sql_yacc.yy
    1.471 06/06/27 00:50:52 konstantin@stripped +0 -0
    Auto merged

  sql/sql_table.cc
    1.315 06/06/27 00:50:51 konstantin@stripped +0 -0
    Auto merged

  sql/sql_parse.cc
    1.554 06/06/27 00:50:51 konstantin@stripped +0 -0
    Auto merged

  sql/sql_lex.h
    1.219 06/06/27 00:50:50 konstantin@stripped +0 -0
    Auto merged

  sql/sql_insert.cc
    1.193 06/06/27 00:50:50 konstantin@stripped +0 -0
    Auto merged

  sql/sql_db.cc
    1.129 06/06/27 00:50:50 konstantin@stripped +0 -0
    Auto merged

  sql/sql_class.h
    1.290 06/06/27 00:50:50 konstantin@stripped +0 -0
    Auto merged

  sql/sp_head.cc
    1.217 06/06/27 00:50:50 konstantin@stripped +0 -0
    Auto merged

  sql/slave.cc
    1.271 06/06/27 00:50:50 konstantin@stripped +0 -0
    Auto merged

  sql/log_event.cc
    1.206 06/06/27 00:50:50 konstantin@stripped +0 -0
    Auto merged

  sql/item_strfunc.cc
    1.271 06/06/27 00:50:50 konstantin@stripped +0 -0
    Auto merged

  mysql-test/t/create.test
    1.80 06/06/27 00:50:50 konstantin@stripped +0 -0
    Auto merged

  mysql-test/r/create.result
    1.118 06/06/27 00:50:49 konstantin@stripped +0 -0
    Auto merged

# 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:	konstantin
# Host:	bodhi.netgear
# Root:	/opt/local/work/mysql-5.0-17199/RESYNC

--- 1.270/sql/item_strfunc.cc	2006-06-21 07:49:28 +04:00
+++ 1.271/sql/item_strfunc.cc	2006-06-27 00:50:50 +04:00
@@ -1667,13 +1667,13 @@
 {
   DBUG_ASSERT(fixed == 1);
   THD *thd= current_thd;
-  if (!thd->db)
+  if (thd->db == NULL)
   {
     null_value= 1;
     return 0;
   }
   else
-    str->copy((const char*) thd->db,(uint) strlen(thd->db),system_charset_info);
+    str->copy(thd->db, thd->db_length, system_charset_info);
   return str;
 }
 

--- 1.205/sql/log_event.cc	2006-06-12 16:54:40 +04:00
+++ 1.206/sql/log_event.cc	2006-06-27 00:50:50 +04:00
@@ -1868,9 +1868,10 @@
     don't suffer from these assignments to 0 as DROP TEMPORARY
     TABLE uses the db.table syntax.
   */
-  thd->db= thd->catalog= 0;	        // prevent db from being freed
+  thd->catalog= 0;
+  thd->reset_db(NULL, 0);               // prevent db from being freed
   thd->query= 0;			// just to be sure
-  thd->query_length= thd->db_length =0;
+  thd->query_length= 0;
   VOID(pthread_mutex_unlock(&LOCK_thread_count));
   close_thread_tables(thd);      
   free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
@@ -2872,7 +2873,7 @@
 
     TABLE_LIST tables;
     bzero((char*) &tables,sizeof(tables));
-    tables.db = thd->db;
+    tables.db= thd->strmake(thd->db, thd->db_length);
     tables.alias = tables.table_name = (char*) table_name;
     tables.lock_type = TL_WRITE;
     tables.updating= 1;
@@ -2967,7 +2968,7 @@
       ex.skip_lines = skip_lines;
       List<Item> field_list;
       thd->main_lex.select_lex.context.resolve_in_table_list_only(&tables);
-      set_fields(thd->db, field_list, &thd->main_lex.select_lex.context);
+      set_fields(tables.db, field_list, &thd->main_lex.select_lex.context);
       thd->variables.pseudo_thread_id= thread_id;
       List<Item> set_fields;
       if (net)
@@ -3014,11 +3015,12 @@
 
 error:
   thd->net.vio = 0; 
-  char *save_db= thd->db;
+  const char *remember_db= thd->db;
   VOID(pthread_mutex_lock(&LOCK_thread_count));
-  thd->db= thd->catalog= 0;
+  thd->catalog= 0;
+  thd->reset_db(NULL, 0);
   thd->query= 0;
-  thd->query_length= thd->db_length= 0;
+  thd->query_length= 0;
   VOID(pthread_mutex_unlock(&LOCK_thread_count));
   close_thread_tables(thd);
   if (thd->query_error)
@@ -3035,7 +3037,7 @@
     }
     slave_print_error(rli,sql_errno,"\
 Error '%s' running LOAD DATA INFILE on table '%s'. Default database: '%s'",
-		      err, (char*)table_name, print_slave_db_safe(save_db));
+		      err, (char*)table_name, print_slave_db_safe(remember_db));
     free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
     return 1;
   }
@@ -3045,7 +3047,7 @@
   {
     slave_print_error(rli,ER_UNKNOWN_ERROR, "\
 Fatal error running LOAD DATA INFILE on table '%s'. Default database: '%s'",
-		      (char*)table_name, print_slave_db_safe(save_db));
+		      (char*)table_name, print_slave_db_safe(remember_db));
     return 1;
   }
 

--- 1.270/sql/slave.cc	2006-06-20 22:46:39 +04:00
+++ 1.271/sql/slave.cc	2006-06-27 00:50:50 +04:00
@@ -1581,9 +1581,8 @@
   // save old db in case we are creating in a different database
   save_db = thd->db;
   save_db_length= thd->db_length;
-  thd->db = (char*)db;
-  DBUG_ASSERT(thd->db != 0);
-  thd->db_length= strlen(thd->db);
+  DBUG_ASSERT(db != 0);
+  thd->reset_db((char*)db, strlen(db));
   mysql_parse(thd, thd->query, packet_len); // run create table
   thd->db = save_db;		// leave things the way the were before
   thd->db_length= save_db_length;
@@ -3713,8 +3712,9 @@
   sql_print_information("Slave I/O thread exiting, read up to log '%s', position %s",
 		  IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff));
   VOID(pthread_mutex_lock(&LOCK_thread_count));
-  thd->query = thd->db = 0; // extra safety
-  thd->query_length= thd->db_length= 0;
+  thd->query= 0; // extra safety
+  thd->query_length= 0;
+  thd->reset_db(NULL, 0);
   VOID(pthread_mutex_unlock(&LOCK_thread_count));
   if (mysql)
   {
@@ -3932,8 +3932,10 @@
     should already have done these assignments (each event which sets these
     variables is supposed to set them to 0 before terminating)).
   */
-  thd->query= thd->db= thd->catalog= 0; 
-  thd->query_length= thd->db_length= 0;
+  thd->catalog= 0; 
+  thd->reset_db(NULL, 0);
+  thd->query= 0; 
+  thd->query_length= 0;
   VOID(pthread_mutex_unlock(&LOCK_thread_count));
   thd->proc_info = "Waiting for slave mutex on exit";
   pthread_mutex_lock(&rli->run_lock);

--- 1.289/sql/sql_class.h	2006-06-16 13:05:45 +04:00
+++ 1.290/sql/sql_class.h	2006-06-27 00:50:50 +04:00
@@ -1571,6 +1571,47 @@
   void restore_sub_statement_state(Sub_statement_state *backup);
   void set_n_backup_active_arena(Query_arena *set, Query_arena *backup);
   void restore_active_arena(Query_arena *set, Query_arena *backup);
+
+  /*
+    Initialize the current database from a NULL-terminated string with length
+  */
+  void set_db(const char *new_db, uint new_db_len)
+  {
+    if (new_db)
+    {
+      /* Do not reallocate memory if current chunk is big enough. */
+      if (db && db_length >= new_db_len)
+        memcpy(db, new_db, new_db_len+1);
+      else
+      {
+        safeFree(db);
+        db= my_strdup_with_length(new_db, new_db_len, MYF(MY_WME));
+      }
+      db_length= db ? new_db_len: 0;
+    }
+  }
+  void reset_db(char *new_db, uint new_db_len)
+  {
+    db= new_db;
+    db_length= new_db_len;
+  }
+  /*
+    Copy the current database to the argument. Use the current arena to
+    allocate memory for a deep copy: current database may be freed after
+    a statement is parsed but before it's executed.
+  */
+  bool copy_db_to(char **p_db, uint *p_db_length)
+  {
+    if (db == NULL)
+    {
+      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+      return TRUE;
+    }
+    *p_db= strmake(db, db_length);
+    if (p_db_length)
+      *p_db_length= db_length;
+    return FALSE;
+  }
 };
 
 
@@ -1916,7 +1957,7 @@
 
 class Table_ident :public Sql_alloc
 {
- public:
+public:
   LEX_STRING db;
   LEX_STRING table;
   SELECT_LEX_UNIT *sel;

--- 1.128/sql/sql_db.cc	2006-05-29 17:26:18 +04:00
+++ 1.129/sql/sql_db.cc	2006-06-27 00:50:50 +04:00
@@ -805,8 +805,7 @@
   {
     if (!(thd->slave_thread)) /* a slave thread will free it itself */
       x_free(thd->db);
-    thd->db= 0;
-    thd->db_length= 0;
+    thd->reset_db(NULL, 0);
   }
   VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
   start_waiting_global_read_lock(thd);
@@ -1218,14 +1217,10 @@
   {
     if (!(thd->slave_thread))
       my_free(dbname, MYF(0));
-    thd->db= NULL;
-    thd->db_length= 0;
+    thd->reset_db(NULL, 0);
   }
   else
-  {
-    thd->db= dbname;				// THD::~THD will free this
-    thd->db_length= db_length;
-  }
+    thd->reset_db(dbname, db_length);          // THD::~THD will free this
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
   if (!no_access_check)
     sctx->db_access= db_access;

--- 1.192/sql/sql_insert.cc	2006-06-19 16:57:36 +04:00
+++ 1.193/sql/sql_insert.cc	2006-06-27 00:50:50 +04:00
@@ -298,9 +298,8 @@
   {
     if (thd->locked_tables)
     {
-      if (find_locked_table(thd,
-			    table_list->db ? table_list->db : thd->db,
-			    table_list->table_name))
+      DBUG_ASSERT(table_list->db); /* Must be set in the parser */
+      if (find_locked_table(thd, table_list->db, table_list->table_name))
       {
 	my_error(ER_DELAYED_INSERT_TABLE_LOCKED, MYF(0),
                  table_list->table_name);
@@ -1329,8 +1328,8 @@
   TABLE *table;
   DBUG_ENTER("delayed_get_table");
 
-  if (!table_list->db)
-    table_list->db=thd->db;
+  /* Must be set in the parser */
+  DBUG_ASSERT(table_list->db);
 
   /* Find the thread which handles this table. */
   if (!(tmp=find_handler(thd,table_list)))
@@ -1369,15 +1368,15 @@
       pthread_mutex_lock(&LOCK_thread_count);
       thread_count++;
       pthread_mutex_unlock(&LOCK_thread_count);
-      if (!(tmp->thd.db=my_strdup(table_list->db,MYF(MY_WME))) ||
-	  !(tmp->thd.query=my_strdup(table_list->table_name,MYF(MY_WME))))
+      tmp->thd.set_db(table_list->db, strlen(table_list->db));
+      tmp->thd.query= my_strdup(table_list->table_name,MYF(MY_WME));
+      if (tmp->thd.db == NULL || tmp->thd.query == NULL)
       {
 	delete tmp;
 	my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
 	goto err1;
       }
       tmp->table_list= *table_list;			// Needed to open table
-      tmp->table_list.db= tmp->thd.db;
       tmp->table_list.alias= tmp->table_list.table_name= tmp->thd.query;
       tmp->lock();
       pthread_mutex_lock(&tmp->mutex);

--- 1.218/sql/sql_lex.h	2006-06-17 00:49:13 +04:00
+++ 1.219/sql/sql_lex.h	2006-06-27 00:50:50 +04:00
@@ -758,6 +758,11 @@
     *this= *state;
   }
 
+  /*
+    Direct addition to the list of query tables.
+    If you are using this function, you must ensure that the table
+    object, in particular table->db member, is initialized.
+  */
   void add_to_query_tables(TABLE_LIST *table)
   {
     *(table->prev_global= query_tables_last)= table;

--- 1.553/sql/sql_parse.cc	2006-06-23 16:09:31 +04:00
+++ 1.554/sql/sql_parse.cc	2006-06-27 00:50:51 +04:00
@@ -93,8 +93,6 @@
   "NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
 };
 
-static char empty_c_string[1]= {0};		// Used for not defined 'db'
-
 #ifdef __WIN__
 static void  test_signal(int sig_ptr)
 {
@@ -300,8 +298,7 @@
       thd->db is saved in caller and needs to be freed by caller if this
       function returns 0
     */
-    thd->db= 0;
-    thd->db_length= 0;
+    thd->reset_db(NULL, 0);
     if (mysql_change_db(thd, db, FALSE))
     {
       /* Send the error to the client */
@@ -341,9 +338,8 @@
     if connect failed. Also in case of 'CHANGE USER' failure, current
     database will be switched to 'no database selected'.
   */
-  thd->db= 0;
-  thd->db_length= 0;
-  
+  thd->reset_db(NULL, 0);
+
   USER_RESOURCES ur;
   int res= acl_getroot(thd, &ur, passwd, passwd_len);
 #ifndef EMBEDDED_LIBRARY
@@ -1316,19 +1312,6 @@
   DBUG_RETURN(0);
 }
 
-    /* This works because items are allocated with sql_alloc() */
-
-void free_items(Item *item)
-{
-  Item *next;
-  DBUG_ENTER("free_items");
-  for (; item ; item=next)
-  {
-    next=item->next;
-    item->delete_self();
-  }
-  DBUG_VOID_RETURN;
-}
 
     /* This works because items are allocated with sql_alloc() */
 
@@ -1340,7 +1323,26 @@
   DBUG_VOID_RETURN;
 }
 
-int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
+/*
+  Handle COM_TABLE_DUMP command
+
+  SYNOPSIS
+    mysql_table_dump
+      thd           thread handle
+      db            database name or an empty string. If empty,
+                    the current database of the connection is used
+      tbl_name      name of the table to dump
+
+  NOTES
+    This function is written to handle one specific command only.
+
+  RETURN VALUE
+    0               success
+    1               error, the error message is set in THD
+*/
+
+static
+int mysql_table_dump(THD* thd, char* db, char* tbl_name)
 {
   TABLE* table;
   TABLE_LIST* table_list;
@@ -1377,7 +1379,7 @@
     goto err;
   }
   net_flush(&thd->net);
-  if ((error= table->file->dump(thd,fd)))
+  if ((error= table->file->dump(thd,-1)))
     my_error(ER_GET_ERRNO, MYF(0), error);
 
 err:
@@ -1627,7 +1629,7 @@
     }
     tbl_name= strmake(db, packet + 1, db_len)+1;
     strmake(tbl_name, packet + db_len + 2, tbl_len);
-    mysql_table_dump(thd, db, tbl_name, -1);
+    mysql_table_dump(thd, db, tbl_name);
     break;
   }
   case COM_CHANGE_USER:
@@ -1801,11 +1803,8 @@
     statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS],
 			&LOCK_status);
     bzero((char*) &table_list,sizeof(table_list));
-    if (!(table_list.db=thd->db))
-    {
-      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+    if (thd->copy_db_to(&table_list.db, 0))
       break;
-    }
     pend= strend(packet);
     thd->convert_string(&conv_name, system_charset_info,
 			packet, (uint) (pend-packet), thd->charset());
@@ -2152,6 +2151,34 @@
 }
 
 
+/*
+  Create a TABLE_LIST object for an INFORMATION_SCHEMA table.
+
+  SYNOPSIS
+    prepare_schema_table()
+      thd              thread handle
+      lex              current lex
+      table_ident      table alias if it's used
+      schema_table_idx the type of the INFORMATION_SCHEMA table to be
+                       created
+
+  DESCRIPTION
+    This function is used in the parser to convert a SHOW or DESCRIBE
+    table_name command to a SELECT from INFORMATION_SCHEMA.
+    It prepares a SELECT_LEX and a TABLE_LIST object to represent the
+    given command as a SELECT parse tree.
+
+  NOTES
+    Due to the way this function works with memory and LEX it cannot
+    be used outside the parser (parse tree transformations outside
+    the parser break PS and SP).
+
+  RETURN VALUE
+    0                 success
+    1                 out of memory or SHOW commands are not allowed
+                      in this version of the server.
+*/
+
 int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
                          enum enum_schema_tables schema_table_idx)
 {
@@ -2179,13 +2206,13 @@
     DBUG_RETURN(1);
 #else
     {
-      char *db= lex->select_lex.db ? lex->select_lex.db : thd->db;
-      if (!db)
+      char *db;
+      if (lex->select_lex.db == NULL &&
+          thd->copy_db_to(&lex->select_lex.db, 0))
       {
-	my_message(ER_NO_DB_ERROR,
-                   ER(ER_NO_DB_ERROR), MYF(0)); /* purecov: inspected */
-        DBUG_RETURN(1);				/* purecov: inspected */
+        DBUG_RETURN(1);
       }
+      db= lex->select_lex.db;
       remove_escape(db);				// Fix escaped '_'
       if (check_db_name(db))
       {
@@ -2202,11 +2229,6 @@
                  db);
 	DBUG_RETURN(1);
       }
-      /*
-        We need to do a copy to make this prepared statement safe if this
-        was thd->db
-      */
-      lex->select_lex.db= thd->strdup(db);
       break;
     }
 #endif
@@ -2739,8 +2761,8 @@
   case SQLCOM_LOAD_MASTER_TABLE:
   {
     DBUG_ASSERT(first_table == all_tables && first_table != 0);
-    if (!first_table->db)
-      first_table->db= thd->db;
+    DBUG_ASSERT(first_table->db); /* Must be set in the parser */
+
     if (check_access(thd, CREATE_ACL, first_table->db,
 		     &first_table->grant.privilege, 0, 0,
                      test(first_table->schema_table)))
@@ -2988,25 +3010,8 @@
 	my_error(ER_WRONG_TABLE_NAME, MYF(0), lex->name);
         goto error;
       }
-      if (!select_lex->db)
-      {
-        /*
-          In the case of ALTER TABLE ... RENAME we should supply the
-          default database if the new name is not explicitly qualified
-          by a database. (Bug #11493)
-        */
-        if (lex->alter_info.flags & ALTER_RENAME)
-        {
-          if (! thd->db)
-          {
-            my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
-            goto error;
-          }
-          select_lex->db= thd->db;
-        }
-        else
-          select_lex->db= first_table->db;
-      }
+      /* Must be set in the parser */
+      DBUG_ASSERT(select_lex->db);
       if (check_access(thd, ALTER_ACL, first_table->db,
 		       &first_table->grant.privilege, 0, 0,
                        test(first_table->schema_table)) ||
@@ -3676,12 +3681,8 @@
   }
   case SQLCOM_ALTER_DB:
   {
-    char *db= lex->name ? lex->name : thd->db;
-    if (!db)
-    {
-      my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
-      break;
-    }
+    char *db= lex->name;
+    DBUG_ASSERT(db); /* Must be set in the parser */
     if (!strip_sp(db) || check_db_name(db))
     {
       my_error(ER_WRONG_DB_NAME, MYF(0), lex->name);
@@ -4130,23 +4131,11 @@
   case SQLCOM_CREATE_SPFUNCTION:
   {
     uint namelen;
-    char *name, *db;
+    char *name;
     int result;
 
     DBUG_ASSERT(lex->sphead != 0);
-
-    if (!lex->sphead->m_db.str || !lex->sphead->m_db.str[0])
-    {
-      if (!thd->db)
-      {
-        my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
-        delete lex->sphead;
-        lex->sphead= 0;
-        goto error;
-      }
-      lex->sphead->m_db.length= strlen(thd->db);
-      lex->sphead->m_db.str= thd->db;
-    }
+    DBUG_ASSERT(lex->sphead->m_db.str); /* Must be initialized in the parser */
 
     if (check_access(thd, CREATE_PROC_ACL, lex->sphead->m_db.str, 0, 0, 0,
                      is_schema_db(lex->sphead->m_db.str)))
@@ -4263,41 +4252,27 @@
     }
 #endif /* NO_EMBEDDED_ACCESS_CHECKS */
 
-    /*
-      We need to copy name and db in order to use them for
-      check_routine_access which is called after lex->sphead has
-      been deleted.
-    */
-    name= thd->strdup(name); 
-    lex->sphead->m_db.str= db= thd->strmake(lex->sphead->m_db.str,
-                                            lex->sphead->m_db.length);
     res= (result= lex->sphead->create(thd));
     if (result == SP_OK)
     {
-      /*
-        We must cleanup the unit and the lex here because
-        sp_grant_privileges calls (indirectly) db_find_routine,
-        which in turn may call MYSQLparse with THD::lex.
-        TODO: fix db_find_routine to use a temporary lex.
-      */
-      lex->unit.cleanup();
-      delete lex->sphead;
-      lex->sphead= 0;
 #ifndef NO_EMBEDDED_ACCESS_CHECKS
       /* only add privileges if really neccessary */
       if (sp_automatic_privileges && !opt_noacl &&
           check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
-      			       db, name,
+      			       lex->sphead->m_db.str, name,
                                lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1))
       {
         close_thread_tables(thd);
-        if (sp_grant_privileges(thd, db, name, 
+        if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
                                 lex->sql_command == SQLCOM_CREATE_PROCEDURE))
           push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
 	  	       ER_PROC_AUTO_GRANT_FAIL,
 		       ER(ER_PROC_AUTO_GRANT_FAIL));
       }
 #endif
+      lex->unit.cleanup();
+      delete lex->sphead;
+      lex->sphead= 0;
       send_ok(thd);
     }
     else
@@ -4712,7 +4687,8 @@
         view_store_options(thd, first_table, &buff);
         buff.append(STRING_WITH_LEN("VIEW "));
         /* Test if user supplied a db (ie: we did not use thd->db) */
-        if (first_table->db != thd->db && first_table->db[0])
+        if (first_table->db && first_table->db[0] &&
+            (thd->db == NULL || strcmp(first_table->db, thd->db)))
         {
           append_identifier(thd, &buff, first_table->db,
                             first_table->db_length);
@@ -5282,7 +5258,7 @@
         (want_access & ~EXTRA_ACL) &&
 	thd->db)
       tables->grant.privilege= want_access;
-    else if (tables->db && tables->db == thd->db)
+    else if (tables->db && thd->db && strcmp(tables->db, thd->db) == 0)
     {
       if (found && !grant_option)		// db already checked
 	tables->grant.privilege=found_access;
@@ -5430,22 +5406,25 @@
 
 static bool check_db_used(THD *thd,TABLE_LIST *tables)
 {
+  char *current_db= NULL;
   for (; tables; tables= tables->next_global)
   {
-    if (!tables->db)
+    if (tables->db == NULL)
     {
-      if (!(tables->db=thd->db))
-      {
-	my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR),
-                   MYF(0));                     /* purecov: tested */
-	return TRUE;				/* purecov: tested */
-      }
+      /*
+        This code never works and should be removed in 5.1.  All tables
+        that are added to the list of tables should already have its
+        database field initialized properly (see st_lex::add_table_to_list).
+      */
+      DBUG_ASSERT(0);
+      if (thd->copy_db_to(&current_db, 0))
+        return TRUE;
+      tables->db= current_db;
     }
   }
   return FALSE;
 }
 
-
 /****************************************************************************
 	Check stack size; Send error if there isn't enough stack to continue
 ****************************************************************************/
@@ -6065,19 +6044,8 @@
     ptr->db= table->db.str;
     ptr->db_length= table->db.length;
   }
-  else if (thd->db)
-  {
-    ptr->db= thd->db;
-    ptr->db_length= thd->db_length;
-  }
-  else
-  {
-    /* The following can't be "" as we may do 'casedn_str()' on it */
-    ptr->db= empty_c_string;
-    ptr->db_length= 0;
-  }
-  if (thd->stmt_arena->is_stmt_prepare_or_first_sp_execute())
-    ptr->db= thd->strdup(ptr->db);
+  else if (thd->copy_db_to(&ptr->db, &ptr->db_length))
+    DBUG_RETURN(0);
 
   ptr->alias= alias_str;
   if (lower_case_table_names && table->table.length)
@@ -7268,6 +7236,8 @@
     my_message(ER_WRONG_VALUE_COUNT, ER(ER_WRONG_VALUE_COUNT), MYF(0));
     DBUG_RETURN(TRUE);
   }
+  if (check_db_used(thd, tables))
+    DBUG_RETURN(TRUE);
   DBUG_RETURN(FALSE);
 }
 

--- 1.314/sql/sql_table.cc	2006-06-23 20:15:34 +04:00
+++ 1.315/sql/sql_table.cc	2006-06-27 00:50:51 +04:00
@@ -2687,7 +2687,8 @@
 
   TABLE_LIST src_tables_list;
   DBUG_ENTER("mysql_create_like_table");
-  src_db= table_ident->db.str ? table_ident->db.str : thd->db;
+  DBUG_ASSERT(table_ident->db.str); /* Must be set in the parser */
+  src_db= table_ident->db.str;
 
   /*
     Validate the source table

--- 1.470/sql/sql_yacc.yy	2006-06-15 22:09:05 +04:00
+++ 1.471/sql/sql_yacc.yy	2006-06-27 00:50:52 +04:00
@@ -1237,12 +1237,18 @@
 	  }
 	| ident
 	  {
+            THD *thd= YYTHD;
+            LEX_STRING db;
 	    if (check_routine_name($1))
             {
 	      my_error(ER_SP_WRONG_NAME, MYF(0), $1.str);
 	      YYABORT;
 	    }
-	    $$= sp_name_current_db_new(YYTHD, $1);
+            if (thd->copy_db_to(&db.str, &db.length))
+              YYABORT;
+	    $$= new sp_name(db, $1);
+            if ($$)
+	      $$->init_qname(YYTHD);
 	  }
 	;
 
@@ -2405,14 +2411,26 @@
         | LIKE table_ident
           {
             LEX *lex=Lex;
+            THD *thd= lex->thd;
             if (!(lex->name= (char *)$2))
               YYABORT;
+            if ($2->db.str == NULL &&
+                thd->copy_db_to(&($2->db.str), &($2->db.length)))
+            {
+              YYABORT;
+            }
           }
         | '(' LIKE table_ident ')'
           {
             LEX *lex=Lex;
+            THD *thd= lex->thd;
             if (!(lex->name= (char *)$3))
               YYABORT;
+            if ($3->db.str == NULL &&
+                thd->copy_db_to(&($3->db.str), &($3->db.length)))
+            {
+              YYABORT;
+            }
           }
         ;
 
@@ -3240,7 +3258,9 @@
 	  lex->key_list.empty();
 	  lex->col_list.empty();
           lex->select_lex.init_order();
-	  lex->select_lex.db=lex->name=0;
+	  lex->select_lex.db=
+            ((TABLE_LIST*) lex->select_lex.table_list.first)->db;
+          lex->name=0;
 	  bzero((char*) &lex->create_info,sizeof(lex->create_info));
 	  lex->create_info.db_type= DB_TYPE_DEFAULT;
 	  lex->create_info.default_table_charset= NULL;
@@ -3258,8 +3278,11 @@
           opt_create_database_options
 	  {
 	    LEX *lex=Lex;
+            THD *thd= Lex->thd;
 	    lex->sql_command=SQLCOM_ALTER_DB;
 	    lex->name= $3;
+            if (lex->name == NULL && thd->copy_db_to(&lex->name, NULL))
+              YYABORT;
 	  }
 	| ALTER PROCEDURE sp_name
 	  {
@@ -3421,14 +3444,20 @@
 	| RENAME opt_to table_ident
 	  {
 	    LEX *lex=Lex;
+            THD *thd= lex->thd;
 	    lex->select_lex.db=$3->db.str;
-	    lex->name= $3->table.str;
+            if (lex->select_lex.db == NULL &&
+                thd->copy_db_to(&lex->select_lex.db, NULL))
+            {
+              YYABORT;
+            }
             if (check_table_name($3->table.str,$3->table.length) ||
                 $3->db.str && check_db_name($3->db.str))
             {
               my_error(ER_WRONG_TABLE_NAME, MYF(0), $3->table.str);
               YYABORT;
             }
+	    lex->name= $3->table.str;
 	    lex->alter_info.flags|= ALTER_RENAME;
 	  }
 	| CONVERT_SYM TO_SYM charset charset_name_or_default opt_collate
@@ -4742,7 +4771,13 @@
 #endif /* HAVE_DLOPEN */
             {
 	      LEX *lex= Lex;
-              sp_name *name= sp_name_current_db_new(YYTHD, $1);
+              THD *thd= lex->thd;
+              LEX_STRING db;
+              if (thd->copy_db_to(&db.str, &db.length))
+                YYABORT;
+              sp_name *name= new sp_name(db, $1);
+              if (name)
+                name->init_qname(thd);
 
               sp_add_used_routine(lex, YYTHD, name, TYPE_ENUM_FUNCTION);
               if ($4)
@@ -8460,7 +8495,9 @@
 	'*'
 	  {
 	    LEX *lex= Lex;
-	    lex->current_select->db= lex->thd->db;
+            THD *thd= lex->thd;
+            if (thd->copy_db_to(&lex->current_select->db, NULL))
+              YYABORT;
 	    if (lex->grant == GLOBAL_ACLS)
 	      lex->grant = DB_ACLS & ~GRANT_ACL;
 	    else if (lex->columns.elements)

--- 1.117/mysql-test/r/create.result	2006-06-04 22:27:36 +04:00
+++ 1.118/mysql-test/r/create.result	2006-06-27 00:50:49 +04:00
@@ -607,7 +607,7 @@
 use mysqltest;
 drop database mysqltest;
 create table test.t1 like x;
-ERROR 42000: Incorrect database name 'NULL'
+ERROR 3D000: No database selected
 drop table if exists test.t1;
 create database mysqltest;
 use mysqltest;

--- 1.79/mysql-test/t/create.test	2006-06-04 22:27:36 +04:00
+++ 1.80/mysql-test/t/create.test	2006-06-27 00:50:50 +04:00
@@ -517,7 +517,7 @@
 create database mysqltest;
 use mysqltest;
 drop database mysqltest;
---error 1102
+--error ER_NO_DB_ERROR 
 create table test.t1 like x;
 --disable_warnings
 drop table if exists test.t1;

--- 1.201/mysql-test/r/sp.result	2006-06-22 19:29:44 +04:00
+++ 1.202/mysql-test/r/sp.result	2006-06-27 00:52:52 +04:00
@@ -4990,6 +4990,52 @@
 DROP FUNCTION bug18037_f1|
 DROP PROCEDURE bug18037_p1|
 DROP PROCEDURE bug18037_p2|
+use test|
+create table t3 (i int)|
+insert into t3 values (1), (2)|
+create database mysqltest1|
+use mysqltest1|
+create function bug17199() returns varchar(2) deterministic return 'ok'|
+use test|
+select *, mysqltest1.bug17199() from t3|
+i	mysqltest1.bug17199()
+1	ok
+2	ok
+use mysqltest1|
+create function bug18444(i int) returns int no sql deterministic return i + 1|
+use test|
+select mysqltest1.bug18444(i) from t3|
+mysqltest1.bug18444(i)
+2
+3
+drop database mysqltest1|
+create database mysqltest1 charset=utf8|
+create database mysqltest2 charset=utf8|
+create procedure mysqltest1.p1()
+begin
+-- alters the default collation of database test 
+alter database character set koi8r;
+end|
+use mysqltest1|
+call p1()|
+show create database mysqltest1|
+Database	Create Database
+mysqltest1	CREATE DATABASE `mysqltest1` /*!40100 DEFAULT CHARACTER SET koi8r */
+show create database mysqltest2|
+Database	Create Database
+mysqltest2	CREATE DATABASE `mysqltest2` /*!40100 DEFAULT CHARACTER SET utf8 */
+alter database mysqltest1 character set utf8|
+use mysqltest2|
+call mysqltest1.p1()|
+show create database mysqltest1|
+Database	Create Database
+mysqltest1	CREATE DATABASE `mysqltest1` /*!40100 DEFAULT CHARACTER SET koi8r */
+show create database mysqltest2|
+Database	Create Database
+mysqltest2	CREATE DATABASE `mysqltest2` /*!40100 DEFAULT CHARACTER SET utf8 */
+drop database mysqltest1|
+drop database mysqltest2|
+use test|
 drop table if exists t3|
 drop procedure if exists bug15217|
 create table t3 as select 1|

--- 1.189/mysql-test/t/sp.test	2006-06-22 19:29:45 +04:00
+++ 1.190/mysql-test/t/sp.test	2006-06-27 00:52:52 +04:00
@@ -5889,6 +5889,52 @@
 DROP PROCEDURE bug18037_p2|
 
 #
+# Bug#17199: "Table not found" error occurs if the query contains a call
+#            to a function from another database.
+#            See also ps.test for an additional test case for this bug.
+#
+use test|
+create table t3 (i int)|
+insert into t3 values (1), (2)|
+create database mysqltest1|
+use mysqltest1|
+create function bug17199() returns varchar(2) deterministic return 'ok'|
+use test|
+select *, mysqltest1.bug17199() from t3|
+#
+# Bug#18444: Fully qualified stored function names don't work correctly
+#            in select statements
+#
+use mysqltest1|
+create function bug18444(i int) returns int no sql deterministic return i + 1|
+use test|
+select mysqltest1.bug18444(i) from t3|
+drop database mysqltest1|
+#
+# Check that current database has no influence to a stored procedure
+#
+create database mysqltest1 charset=utf8|
+create database mysqltest2 charset=utf8|
+create procedure mysqltest1.p1()
+begin
+-- alters the default collation of database test 
+  alter database character set koi8r;
+end|
+use mysqltest1|
+call p1()|
+show create database mysqltest1|
+show create database mysqltest2|
+alter database mysqltest1 character set utf8|
+use mysqltest2|
+call mysqltest1.p1()|
+show create database mysqltest1|
+show create database mysqltest2|
+drop database mysqltest1|
+drop database mysqltest2|
+#
+# Restore the old environemnt
+use test|
+#
 # Bug#15217 "Using a SP cursor on a table created with PREPARE fails with
 #           weird error". Check that the code that is supposed to work at
 #           the first execution of a stored procedure actually works for

--- 1.216/sql/sp_head.cc	2006-06-26 06:48:10 +04:00
+++ 1.217/sql/sp_head.cc	2006-06-27 00:50:50 +04:00
@@ -376,24 +376,6 @@
 	  m_name.length, m_name.str);
 }
 
-sp_name *
-sp_name_current_db_new(THD *thd, LEX_STRING name)
-{
-  sp_name *qname;
-
-  if (! thd->db)
-    qname= new sp_name(name);
-  else
-  {
-    LEX_STRING db;
-
-    db.length= strlen(thd->db);
-    db.str= thd->strmake(thd->db, db.length);
-    qname= new sp_name(db, name);
-  }
-  qname->init_qname(thd);
-  return qname;
-}
 
 /*
   Check that the name 'ident' is ok. It's assumed to be an 'ident'
@@ -504,27 +486,20 @@
   /* During parsing, we must use thd->mem_root */
   MEM_ROOT *root= thd->mem_root;
 
+  DBUG_ASSERT(name);
+  /* Must be initialized in the parser */
+  DBUG_ASSERT(name->m_db.str && name->m_db.length);
+
   /* We have to copy strings to get them into the right memroot */
-  if (name)
-  {
-    m_db.length= name->m_db.length;
-    if (name->m_db.length == 0)
-      m_db.str= NULL;
-    else
-      m_db.str= strmake_root(root, name->m_db.str, name->m_db.length);
-    m_name.length= name->m_name.length;
-    m_name.str= strmake_root(root, name->m_name.str, name->m_name.length);
-
-    if (name->m_qname.length == 0)
-      name->init_qname(thd);
-    m_qname.length= name->m_qname.length;
-    m_qname.str= strmake_root(root, name->m_qname.str, m_qname.length);
-  }
-  else if (thd->db)
-  {
-    m_db.length= thd->db_length;
-    m_db.str= strmake_root(root, thd->db, m_db.length);
-  }
+  m_db.length= name->m_db.length;
+  m_db.str= strmake_root(root, name->m_db.str, name->m_db.length);
+  m_name.length= name->m_name.length;
+  m_name.str= strmake_root(root, name->m_name.str, name->m_name.length);
+
+  if (name->m_qname.length == 0)
+    name->init_qname(thd);
+  m_qname.length= name->m_qname.length;
+  m_qname.str= strmake_root(root, name->m_qname.str, m_qname.length);
 
   if (m_param_begin && m_param_end)
   {
@@ -933,7 +908,8 @@
 sp_head::execute(THD *thd)
 {
   DBUG_ENTER("sp_head::execute");
-  char olddb[128];
+  char old_db_buf[NAME_LEN+1];
+  LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) };
   bool dbchanged;
   sp_rcontext *ctx;
   bool err_status= FALSE;
@@ -980,10 +956,8 @@
                m_first_instance->m_last_cached_sp == this) ||
               (m_recursion_level + 1 == m_next_cached_sp->m_recursion_level));
 
-  dbchanged= FALSE;
   if (m_db.length &&
-      (err_status= sp_use_new_db(thd, m_db.str, olddb, sizeof(olddb), 0,
-                                 &dbchanged)))
+      (err_status= sp_use_new_db(thd, m_db, &old_db, 0, &dbchanged)))
     goto done;
 
   if ((ctx= thd->spcont))
@@ -1154,10 +1128,10 @@
   {
     /*
       No access check when changing back to where we came from.
-      (It would generate an error from mysql_change_db() when olddb=="")
+      (It would generate an error from mysql_change_db() when old_db=="")
     */
     if (! thd->killed)
-      err_status|= mysql_change_db(thd, olddb, 1);
+      err_status|= mysql_change_db(thd, old_db.str, 1);
   }
   m_flags&= ~IS_INVOKED;
   DBUG_PRINT("info",
@@ -1815,9 +1789,6 @@
                       (ulong) &mem_root, (ulong) &thd->mem_root));
   free_list= thd->free_list; // Keep the old list
   thd->free_list= NULL;	// Start a new one
-  /* Copy the db, since substatements will point to it */
-  m_thd_db= thd->db;
-  thd->db= thd->strmake(thd->db, thd->db_length);
   m_thd= thd;
   DBUG_VOID_RETURN;
 }
@@ -1833,7 +1804,6 @@
   DBUG_PRINT("info", ("mem_root 0x%lx returned from thd mem root 0x%lx",
                       (ulong) &mem_root, (ulong) &thd->mem_root));
   thd->free_list= flist;	// Restore the old one
-  thd->db= m_thd_db;		// Restore the original db pointer
   thd->mem_root= m_thd_root;
   m_thd= NULL;
   DBUG_VOID_RETURN;
Thread
bk commit into 5.0 tree (konstantin:1.2200)konstantin26 Jun