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 Kodinov | 2 Jun |