List:Commits« Previous MessageNext Message »
From:Georgi Kodinov Date:June 2 2010 8:43am
Subject:bzr push into mysql-5.0 branch (Georgi.Kodinov:2866 to 2867)
View as plain text  
 2867 Georgi Kodinov	2010-06-02
      changed the tree name

    modified:
      .bzr-mysql/default.conf
 2866 Georgi Kodinov	2010-06-01 [merge]
      merged mysql-5.0 to mysql-5.0-bugteam

    modified:
      configure.in
=== modified file 'mysql-test/r/join_outer.result'
--- a/mysql-test/r/join_outer.result	2007-05-26 17:33:01 +0000
+++ b/mysql-test/r/join_outer.result	2010-05-06 08:45:00 +0000
@@ -1254,3 +1254,33 @@ SELECT * FROM t1 LEFT JOIN t2 ON e<>0 WH
 c	e	d
 1	0	NULL
 DROP TABLE t1,t2;
+#
+# Bug#52357: Assertion failed: join->best_read in greedy_search 
+# optimizer_search_depth=0
+#
+CREATE TABLE t1( a INT );
+INSERT INTO t1 VALUES (1),(2);
+SET optimizer_search_depth = 0;
+# Should not core dump on query preparation
+EXPLAIN
+SELECT 1
+FROM t1 tt3 LEFT  OUTER JOIN t1 tt4 ON 1
+LEFT  OUTER JOIN t1 tt5 ON 1
+LEFT  OUTER JOIN t1 tt6 ON 1
+LEFT  OUTER JOIN t1 tt7 ON 1
+LEFT  OUTER JOIN t1 tt8 ON 1
+RIGHT OUTER JOIN t1 tt2 ON 1
+RIGHT OUTER JOIN t1 tt1 ON 1
+STRAIGHT_JOIN    t1 tt9 ON 1;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	tt1	ALL	NULL	NULL	NULL	NULL	2	
+1	SIMPLE	tt2	ALL	NULL	NULL	NULL	NULL	2	
+1	SIMPLE	tt3	ALL	NULL	NULL	NULL	NULL	2	
+1	SIMPLE	tt4	ALL	NULL	NULL	NULL	NULL	2	
+1	SIMPLE	tt5	ALL	NULL	NULL	NULL	NULL	2	
+1	SIMPLE	tt6	ALL	NULL	NULL	NULL	NULL	2	
+1	SIMPLE	tt7	ALL	NULL	NULL	NULL	NULL	2	
+1	SIMPLE	tt8	ALL	NULL	NULL	NULL	NULL	2	
+1	SIMPLE	tt9	ALL	NULL	NULL	NULL	NULL	2	
+SET optimizer_search_depth = DEFAULT;
+DROP TABLE t1;

=== modified file 'mysql-test/t/join_outer.test'
--- a/mysql-test/t/join_outer.test	2007-05-26 17:33:01 +0000
+++ b/mysql-test/t/join_outer.test	2010-05-06 08:45:00 +0000
@@ -861,3 +861,27 @@ SELECT * FROM t1 LEFT JOIN t2 ON e<>0 WH
 
 DROP TABLE t1,t2;
 
+ 
+--echo #
+--echo # Bug#52357: Assertion failed: join->best_read in greedy_search 
+--echo # optimizer_search_depth=0
+--echo #
+CREATE TABLE t1( a INT );
+
+INSERT INTO t1 VALUES (1),(2);
+SET optimizer_search_depth = 0;
+
+--echo # Should not core dump on query preparation
+EXPLAIN
+SELECT 1
+FROM t1 tt3 LEFT  OUTER JOIN t1 tt4 ON 1
+            LEFT  OUTER JOIN t1 tt5 ON 1
+            LEFT  OUTER JOIN t1 tt6 ON 1
+            LEFT  OUTER JOIN t1 tt7 ON 1
+            LEFT  OUTER JOIN t1 tt8 ON 1
+            RIGHT OUTER JOIN t1 tt2 ON 1
+            RIGHT OUTER JOIN t1 tt1 ON 1
+            STRAIGHT_JOIN    t1 tt9 ON 1;
+
+SET optimizer_search_depth = DEFAULT;
+DROP TABLE t1;

=== modified file 'sql/item.h'
--- a/sql/item.h	2009-04-01 11:02:26 +0000
+++ b/sql/item.h	2010-05-11 14:21:05 +0000
@@ -470,6 +470,13 @@ public:
   my_string name;			/* Name from select */
   /* Original item name (if it was renamed)*/
   my_string orig_name;
+  /**
+     Intrusive list pointer for free list. If not null, points to the next
+     Item on some Query_arena's free list. For instance, stored procedures
+     have their own Query_arena's.
+     
+     @see Query_arena::free_list
+  */
   Item *next;
   uint32 max_length;
   uint name_length;                     /* Length of name */

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-05-19 18:02:53 +0000
+++ b/sql/sql_parse.cc	2010-06-01 11:28:58 +0000
@@ -493,6 +493,7 @@ int check_user(THD *thd, enum enum_serve
       }
       send_ok(thd);
       thd->password= test(passwd_len);          // remember for error messages 
+#ifndef EMBEDDED_LIBRARY
       /*
         Allow the network layer to skip big packets. Although a malicious
         authenticated session might use this to trick the server to read
@@ -500,6 +501,7 @@ int check_user(THD *thd, enum enum_serve
         that needs to be preserved as to not break backwards compatibility.
       */
       thd->net.skip_big_packet= TRUE;
+#endif
       /* Ready to handle queries */
       DBUG_RETURN(0);
     }
@@ -1411,8 +1413,10 @@ end:
 }
 
 
-    /* This works because items are allocated with sql_alloc() */
-
+/**
+   This works because items are allocated with sql_alloc().
+   @note The function also handles null pointers (empty list).
+*/
 void cleanup_items(Item *item)
 {
   DBUG_ENTER("cleanup_items");  
@@ -1430,6 +1434,7 @@ void cleanup_items(Item *item)
       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
+      tbl_len       its length
 
   NOTES
     This function is written to handle one specific command only.
@@ -1440,7 +1445,7 @@ void cleanup_items(Item *item)
 */
 
 static
-int mysql_table_dump(THD* thd, char* db, char* tbl_name)
+int mysql_table_dump(THD* thd, char* db, char* tbl_name, uint tbl_len)
 {
   TABLE* table;
   TABLE_LIST* table_list;
@@ -1459,6 +1464,11 @@ int mysql_table_dump(THD* thd, char* db,
     my_error(ER_WRONG_DB_NAME ,MYF(0), db ? db : "NULL");
     goto err;
   }
+  if (!tbl_name || check_table_name(tbl_name, tbl_len))
+  {
+    my_error(ER_WRONG_TABLE_NAME , MYF(0), tbl_name ? tbl_name : "NULL");
+    goto err;
+  }
   if (lower_case_table_names)
     my_casedn_str(files_charset_info, tbl_name);
   remove_escape(table_list->table_name);
@@ -1469,7 +1479,7 @@ int mysql_table_dump(THD* thd, char* db,
   if (check_one_table_access(thd, SELECT_ACL, table_list))
     goto err;
   thd->free_list = 0;
-  thd->set_query(tbl_name, (uint) strlen(tbl_name));
+  thd->set_query(tbl_name, tbl_len);
   if ((error = mysqld_dump_create_info(thd, table_list, -1)))
   {
     my_error(ER_GET_ERRNO, MYF(0), my_errno);
@@ -1836,7 +1846,7 @@ bool dispatch_command(enum enum_server_c
     }
     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);
+    mysql_table_dump(thd, db, tbl_name, tbl_len);
     break;
   }
   case COM_CHANGE_USER:

=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc	2010-04-26 20:06:00 +0000
+++ b/sql/sql_select.cc	2010-05-06 08:45:00 +0000
@@ -8706,6 +8706,39 @@ static bool check_interleaving_with_nj(J
 /*
   Nested joins perspective: Remove the last table from the join order
 
+  The algorithm is the reciprocal of check_interleaving_with_nj(), hence
+  parent join nest nodes are updated only when the last table in its child
+  node is removed. The ASCII graphic below will clarify.
+
+  %A table nesting such as <tt> t1 x [ ( t2 x t3 ) x ( t4 x t5 ) ] </tt>is
+  represented by the below join nest tree.
+
+  @verbatim
+                     NJ1
+                  _/ /  \
+                _/  /    NJ2
+              _/   /     / \ 
+             /    /     /   \
+   t1 x [ (t2 x t3) x (t4 x t5) ]
+  @endverbatim
+
+  At the point in time when check_interleaving_with_nj() adds the table t5 to
+  the query execution plan, QEP, it also directs the node named NJ2 to mark
+  the table as covered. NJ2 does so by incrementing its @c counter
+  member. Since all of NJ2's tables are now covered by the QEP, the algorithm
+  proceeds up the tree to NJ1, incrementing its counter as well. All join
+  nests are now completely covered by the QEP.
+
+  restore_prev_nj_state() does the above in reverse. As seen above, the node
+  NJ1 contains the nodes t2, t3, and NJ2. Its counter being equal to 3 means
+  that the plan covers t2, t3, and NJ2, @e and that the sub-plan (t4 x t5)
+  completely covers NJ2. The removal of t5 from the partial plan will first
+  decrement NJ2's counter to 1. It will then detect that NJ2 went from being
+  completely to partially covered, and hence the algorithm must continue
+  upwards to NJ1 and decrement its counter to 2. %A subsequent removal of t4
+  will however not influence NJ1 since it did not un-cover the last table in
+  NJ2.
+
   SYNOPSIS
     restore_prev_nj_state()
       last  join table to remove, it is assumed to be the last in current 
@@ -8722,19 +8755,20 @@ static void restore_prev_nj_state(JOIN_T
 {
   TABLE_LIST *last_emb= last->table->pos_in_table_list->embedding;
   JOIN *join= last->join;
-  while (last_emb)
+  for (;last_emb != NULL; last_emb= last_emb->embedding)
   {
-    if (!(--last_emb->nested_join->counter))
-      join->cur_embedding_map&= ~last_emb->nested_join->nj_map;
-    else if (last_emb->nested_join->join_list.elements-1 ==
-             last_emb->nested_join->counter) 
-    {
-      join->cur_embedding_map|= last_emb->nested_join->nj_map;
-      break;
-    }
-    else
+    NESTED_JOIN *nest= last_emb->nested_join;
+    DBUG_ASSERT(nest->counter > 0);
+    
+    bool was_fully_covered= nest->is_fully_covered();
+    
+    if (--nest->counter == 0)
+      join->cur_embedding_map&= ~nest->nj_map;
+    
+    if (!was_fully_covered)
       break;
-    last_emb= last_emb->embedding;
+    
+    join->cur_embedding_map|= nest->nj_map;
   }
 }
 

=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc	2009-12-13 23:58:16 +0000
+++ b/sql/sql_update.cc	2010-05-11 14:21:05 +0000
@@ -908,8 +908,9 @@ reopen_tables:
       items from 'fields' list, so the cleanup above is necessary to.
     */
     cleanup_items(thd->free_list);
-
+    cleanup_items(thd->stmt_arena->free_list);
     close_tables_for_reopen(thd, &table_list);
+
     goto reopen_tables;
   }
 

=== modified file 'sql/table.h'
--- a/sql/table.h	2009-08-21 14:10:55 +0000
+++ b/sql/table.h	2010-05-06 08:45:00 +0000
@@ -910,7 +910,11 @@ typedef struct st_nested_join
   List<TABLE_LIST>  join_list;       /* list of elements in the nested join */
   table_map         used_tables;     /* bitmap of tables in the nested join */
   table_map         not_null_tables; /* tables that rejects nulls           */
-  struct st_join_table *first_nested;/* the first nested table in the plan  */
+  /**
+    Used for pointing out the first table in the plan being covered by this
+    join nest. It is used exclusively within make_outerjoin_info().
+   */
+  struct st_join_table *first_nested;
   /* 
     Used to count tables in the nested join in 2 isolated places:
     1. In make_outerjoin_info(). 
@@ -920,6 +924,15 @@ typedef struct st_nested_join
   */
   uint              counter;
   nested_join_map   nj_map;          /* Bit used to identify this nested join*/
+  /**
+     True if this join nest node is completely covered by the query execution
+     plan. This means two things.
+
+     1. All tables on its @c join_list are covered by the plan.
+
+     2. All child join nest nodes are fully covered.
+   */
+  bool is_fully_covered() const { return join_list.elements == counter; }
 } NESTED_JOIN;
 
 

=== modified file 'tests/mysql_client_test.c'
--- a/tests/mysql_client_test.c	2010-05-19 18:02:53 +0000
+++ b/tests/mysql_client_test.c	2010-06-01 11:28:58 +0000
@@ -16720,6 +16720,43 @@ static void test_bug53371()
 }
 
 
+static void test_bug53907()
+{
+  int rc;
+  char buf[] = "\x4test\x14../client_test_db/t1";
+
+  myheader("test_bug53907");
+
+  rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+  myquery(rc);
+  rc= mysql_query(mysql, "DROP DATABASE IF EXISTS bug53907");
+  myquery(rc);
+  rc= mysql_query(mysql, "DROP USER 'testbug'@localhost");
+
+  rc= mysql_query(mysql, "CREATE TABLE t1 (a INT)");
+  myquery(rc);
+  rc= mysql_query(mysql, "CREATE DATABASE bug53907");
+  myquery(rc);
+  rc= mysql_query(mysql, "GRANT SELECT ON bug53907.* to 'testbug'@localhost");
+  myquery(rc);
+
+  rc= mysql_change_user(mysql, "testbug", NULL, "bug53907");
+  myquery(rc);
+
+  rc= simple_command(mysql, COM_TABLE_DUMP, buf, sizeof(buf), 0);
+  DIE_UNLESS(mysql_errno(mysql) == 1103); /* ER_WRONG_TABLE_NAME */
+
+  rc= mysql_change_user(mysql, opt_user, opt_password, current_db);
+  myquery(rc);
+  rc= mysql_query(mysql, "DROP TABLE t1");
+  myquery(rc);
+  rc= mysql_query(mysql, "DROP DATABASE bug53907");
+  myquery(rc);
+  rc= mysql_query(mysql, "DROP USER 'testbug'@localhost");
+  myquery(rc);
+}
+
+
 /*
   Read and parse arguments and MySQL options from my.cnf
 */
@@ -17024,6 +17061,7 @@ static struct my_tests_st my_tests[]= {
   { "test_bug20023", test_bug20023 },
   { "test_bug45010", test_bug45010 },
   { "test_bug53371", test_bug53371 },
+  { "test_bug53907", test_bug53907 },
   { 0, 0 }
 };
 


Attachment: [text/bzr-bundle] bzr/georgi.kodinov@oracle.com-20100602084237-ohj84dfs8yocsho0.bundle
Thread
bzr push into mysql-5.0 branch (Georgi.Kodinov:2866 to 2867) Georgi Kodinov2 Jun