MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:kroki Date:July 28 2006 11:06am
Subject:bk commit into 5.0 tree (kroki:1.2237) BUG#16581
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of tomash. When tomash does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2006-07-28 15:06:23+04:00, kroki@stripped +4 -0
  Bug#16581: deadlock: server and client both read from connection in
             'conc_sys' test
  
  Concurrent execution of SELECT involing at least two INFORMATION_SCHEMA
  tables, DROP DATABASE statement and DROP TABLE statement could have
  resulted in stalled connection for this SELECT statement.
  
  The problem was that for the first query of a join there was a race
  between select from I_S.TABLES and DROP DATABASE, and the error (no
  such database) was prepared to be send to the client, but the join
  processing was continued.  On second query to I_S.COLUMNS there was a
  race with DROP TABLE, but this error (no such table) was downgraded to
  warning, and thd->net.report_error was reset.  And so neither result
  nor error was sent to the client.
  
  The solution is to stop join processing once it is clear we are going
  to report a error, and also to downgrade to warnings file system errors
  like 'no such database' (unless we are in the 'SHOW' command), because
  I_S is designed not to use locks and the query to I_S should not abort
  if something is dropped in the middle.
  
  No test case is provided since this bug is a result of a race, and is
  timing dependant.  But we test that plain SHOW TABLES and SHOW COLUMNS
  give a error if there is no such database or a table respectively.

  mysql-test/r/show_check.result@stripped, 2006-07-28 15:06:20+04:00, kroki@stripped +4 -0
    Add result for the test that SHOW TABLES and SHOW COLUMNS give a error
    if there is no such database or a table respectively.

  mysql-test/t/show_check.test@stripped, 2006-07-28 15:06:20+04:00, kroki@stripped +11 -0
    Add test case that SHOW TABLES and SHOW COLUMNS give a error
    if there is no such database or a table respectively.

  sql/mysql_priv.h@stripped, 2006-07-28 15:06:21+04:00, kroki@stripped +0 -2
    Remove prototype of mysql_find_files(), which is made static under
    find_files() name.

  sql/sql_show.cc@stripped, 2006-07-28 15:06:21+04:00, kroki@stripped +66 -15
    Rename mysql_find_files() to find_files() and make it static.
    Return FIND_FILES_OK for success, FIND_FILES_OOM for out of memory,
    and FIND_FILES_DIR for directory reading error.
    Downgrade error to warning in get_all_tables() if it is a
    FIND_FILES_DIR error, and we are not in the 'SHOW' command.
    Once 'result' is set to 1 in get_schema_tables_result(), there's no
    need in continuing iterations, as we are about to return a error.

# 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:	kroki
# Host:	moonlight.intranet
# Root:	/home/tomash/src/mysql_ab/mysql-5.0-bug16581

--- 1.398/sql/mysql_priv.h	2006-07-28 15:06:32 +04:00
+++ 1.399/sql/mysql_priv.h	2006-07-28 15:06:32 +04:00
@@ -865,8 +865,6 @@ bool mysqld_show_create_db(THD *thd, cha
 void mysqld_list_processes(THD *thd,const char *user,bool verbose);
 int mysqld_show_status(THD *thd);
 int mysqld_show_variables(THD *thd,const char *wild);
-int mysql_find_files(THD *thd,List<char> *files, const char *db,
-                const char *path, const char *wild, bool dir);
 bool mysqld_show_storage_engines(THD *thd);
 bool mysqld_show_privileges(THD *thd);
 bool mysqld_show_column_types(THD *thd);

--- 1.323/sql/sql_show.cc	2006-07-28 15:06:33 +04:00
+++ 1.324/sql/sql_show.cc	2006-07-28 15:06:33 +04:00
@@ -250,9 +250,35 @@ bool mysqld_show_column_types(THD *thd)
 }
 
 
-int
-mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
-                 const char *wild, bool dir)
+/*
+  find_files() - find files in a given directory.
+
+  SYNOPSIS
+    find_files()
+    thd                 thread handler
+    files               put found files in this list
+    db                  database name to set in TABLE_LIST structure
+    path                path to database
+    wild                filter for found files
+    dir                 read databases in path if TRUE, read .frm files in
+                        database otherwise
+
+  RETURN
+    FIND_FILES_OK       success
+    FIND_FILES_OOM      out of memory error
+    FIND_FILES_DIR      no such directory, or directory can't be read
+*/
+
+enum find_files_result {
+  FIND_FILES_OK,
+  FIND_FILES_OOM,
+  FIND_FILES_DIR
+};
+
+static
+find_files_result
+find_files(THD *thd, List<char> *files, const char *db,
+           const char *path, const char *wild, bool dir)
 {
   uint i;
   char *ext;
@@ -262,7 +288,7 @@ mysql_find_files(THD *thd,List<char> *fi
   uint col_access=thd->col_access;
 #endif
   TABLE_LIST table_list;
-  DBUG_ENTER("mysql_find_files");
+  DBUG_ENTER("find_files");
 
   if (wild && !wild[0])
     wild=0;
@@ -275,7 +301,7 @@ mysql_find_files(THD *thd,List<char> *fi
       my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db);
     else
       my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path, my_errno);
-    DBUG_RETURN(-1);
+    DBUG_RETURN(FIND_FILES_DIR);
   }
 
   for (i=0 ; i < (uint) dirp->number_off_files  ; i++)
@@ -337,7 +363,7 @@ mysql_find_files(THD *thd,List<char> *fi
     if (files->push_back(thd->strdup(file->name)))
     {
       my_dirend(dirp);
-      DBUG_RETURN(-1);
+      DBUG_RETURN(FIND_FILES_OOM);
     }
   }
   DBUG_PRINT("info",("found: %d files", files->elements));
@@ -345,7 +371,7 @@ mysql_find_files(THD *thd,List<char> *fi
 
   VOID(ha_find_files(thd,db,path,wild,dir,files));
 
-  DBUG_RETURN(0);
+  DBUG_RETURN(FIND_FILES_OK);
 }
 
 
@@ -2000,8 +2026,8 @@ enum enum_schema_tables get_schema_table
                           wild string otherwise it's db name; 
 
   RETURN
-    1	                  error
-    0	                  success
+    zero                  success
+    non-zero              error
 */
 
 int make_db_list(THD *thd, List<char> *files,
@@ -2027,8 +2053,8 @@ int make_db_list(THD *thd, List<char> *f
       if (files->push_back(thd->strdup(information_schema_name.str)))
         return 1;
     }
-    return mysql_find_files(thd, files, NullS, mysql_data_home,
-                            idx_field_vals->db_value, 1);
+    return (find_files(thd, files, NullS, mysql_data_home,
+                       idx_field_vals->db_value, 1) != FIND_FILES_OK);
   }
 
   /*
@@ -2055,7 +2081,8 @@ int make_db_list(THD *thd, List<char> *f
   if (files->push_back(thd->strdup(information_schema_name.str)))
     return 1;
   *with_i_schema= 1;
-  return mysql_find_files(thd, files, NullS, mysql_data_home, NullS, 1);
+  return (find_files(thd, files, NullS,
+                     mysql_data_home, NullS, 1) != FIND_FILES_OK);
 }
 
 
@@ -2204,9 +2231,28 @@ int get_all_tables(THD *thd, TABLE_LIST 
         strxmov(path, mysql_data_home, "/", base_name, NullS);
         end= path + (len= unpack_dirname(path,path));
         len= FN_LEN - len;
-        if (mysql_find_files(thd, &files, base_name, 
-                             path, idx_field_vals.table_value, 0))
-          goto err;
+        find_files_result res= find_files(thd, &files, base_name, 
+                                          path, idx_field_vals.table_value, 0);
+        if (res != FIND_FILES_OK)
+        {
+          /*
+            Downgrade errors about problems with database directory to
+            warnings if this is not a 'SHOW' command.  Another thread
+            may have dropped database, and we may still have a name
+            for that directory.
+          */
+          if (res == FIND_FILES_DIR && lex->orig_sql_command == SQLCOM_END)
+          {
+            push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                         thd->net.last_errno, thd->net.last_error);
+            thd->clear_error();
+            continue;
+          }
+          else
+          {
+            goto err;
+          }
+        }
         if (lower_case_table_names)
           orig_base_name= thd->strdup(base_name);
       }
@@ -3969,7 +4015,12 @@ bool get_schema_tables_result(JOIN *join
 
       if (table_list->schema_table->fill_table(thd, table_list,
                                                tab->select_cond))
+      {
         result= 1;
+        join->error= 1;
+        table_list->is_schema_table_processed= TRUE;
+        break;
+      }
       table_list->is_schema_table_processed= TRUE;
     }
   }

--- 1.77/mysql-test/r/show_check.result	2006-07-28 15:06:33 +04:00
+++ 1.78/mysql-test/r/show_check.result	2006-07-28 15:06:33 +04:00
@@ -625,3 +625,7 @@ View	Create View
 v1	CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select sql_cache 1 AS `1`
 DROP PROCEDURE p1;
 DROP VIEW v1;
+SHOW TABLES FROM no_such_database;
+ERROR 42000: Unknown database 'no_such_database'
+SHOW COLUMNS FROM no_such_table;
+ERROR 42S02: Table 'test.no_such_table' doesn't exist

--- 1.57/mysql-test/t/show_check.test	2006-07-28 15:06:33 +04:00
+++ 1.58/mysql-test/t/show_check.test	2006-07-28 15:06:33 +04:00
@@ -495,4 +495,15 @@ SHOW CREATE VIEW v1;
 DROP PROCEDURE p1;
 DROP VIEW v1;
 
+
+#
+# Check that SHOW TABLES and SHOW COLUMNS give a error if there is no
+# referenced database and table respectively.
+#
+--error ER_BAD_DB_ERROR
+SHOW TABLES FROM no_such_database;
+--error ER_NO_SUCH_TABLE
+SHOW COLUMNS FROM no_such_table;
+
+
 # End of 5.0 tests.
Thread
bk commit into 5.0 tree (kroki:1.2237) BUG#16581kroki28 Jul