Bug #37904 SELECT FROM dual WHERE in-subquery causes server crash
Submitted: 6 Jul 2008 15:59 Modified: 7 Sep 2008 22:21
Reporter: Davi Arnaut (OCA) Email Updates:
Status: Duplicate Impact on me:
None 
Category:MySQL Server: Optimizer Severity:S2 (Serious)
Version:6.0 OS:Any
Assigned to: Assigned Account CPU Architecture:Any
Tags: =any, =some, crash, IN, subquery

[6 Jul 2008 15:59] Davi Arnaut
Description:
Selecting from a dummy table (FROM DUAL) with a subquery comparison using the IN, =ANY or =SOME predicates causes a server crash.

How to repeat:
CREATE TABLE t1 (a INT);
SELECT 1 FROM DUAL WHERE 1 = SOME (SELECT 1 FROM t1);
# OR
SELECT 1 FROM DUAL WHERE 1 ANY (SELECT 1 FROM t1);

Suggested fix:
The code in sql_select.cc around lines 3246 and 3248 looks pretty strange. It seems the for loop is used to reach the last leaf tables in the parent and it connects the last one with the leaf tables of the subquery.

3246├>  for (tl= parent_lex->leaf_tables; tl->next_leaf; tl= tl->next_leaf);
3247│   tl->next_leaf= subq_lex->leaf_tables;
3248│   last_leaf= tl;

The problem appears to be that the case where there are no leaf tables in the parent query is not robustly handled. Someone should review this code, it has a few TODO notes.

=== modified file 'sql/sql_select.cc'
--- sql/sql_select.cc	2008-06-28 11:00:59 +0000
+++ sql/sql_select.cc	2008-07-06 15:57:29 +0000
@@ -3228,7 +3228,7 @@ bool convert_subq_to_sj(JOIN *parent_joi
   st_select_lex *subq_lex= subq_pred->unit->first_select();
   nested_join->join_list.empty();
   List_iterator_fast<TABLE_LIST> li(subq_lex->top_join_list);
-  TABLE_LIST *tl, *last_leaf;
+  TABLE_LIST *tl;
   while ((tl= li++))
   {
     tl->embedding= sj_nest;
@@ -3243,17 +3243,22 @@ bool convert_subq_to_sj(JOIN *parent_joi
     NOTE: We actually insert them at the front! That's because the order is
           reversed in this list.
   */
-  for (tl= parent_lex->leaf_tables; tl->next_leaf; tl= tl->next_leaf);
-  tl->next_leaf= subq_lex->leaf_tables;
-  last_leaf= tl;
+  for (tl= parent_lex->leaf_tables; tl && tl->next_leaf; tl= tl->next_leaf);
+
+  if (tl)
+    tl->next_leaf= subq_lex->leaf_tables;
+  else
+    parent_lex->leaf_tables= subq_lex->leaf_tables;
 
   /*
     Same as above for next_local chain
     (a theory: a next_local chain always starts with ::leaf_tables
      because view's tables are inserted after the view)
   */
-  for (tl= parent_lex->leaf_tables; tl->next_local; tl= tl->next_local);
-  tl->next_local= subq_lex->leaf_tables;
+  for (tl= parent_lex->leaf_tables; tl && tl->next_local; tl= tl->next_local);
+
+  if (tl)
+    tl->next_local= subq_lex->leaf_tables;
 
   /* A theory: no need to re-connect the next_global chain */
[6 Jul 2008 17:46] MySQL Verification Team
Thank you for the bug report.

Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...
00000001403B3A37    mysqld.exe!convert_subq_to_sj()[sql_select.cc:3246]
00000001403B48F8    mysqld.exe!JOIN::flatten_subqueries()[sql_select.cc:3442]
00000001403B30FE    mysqld.exe!mysql_select()[sql_select.cc:2980]
00000001403A9664    mysqld.exe!handle_select()[sql_select.cc:302]
0000000140364AAB    mysqld.exe!execute_sqlcom_select()[sql_parse.cc:4847]
000000014035B100    mysqld.exe!mysql_execute_command()[sql_parse.cc:2015]
0000000140367238    mysqld.exe!mysql_parse()[sql_parse.cc:5815]
0000000140358F39    mysqld.exe!dispatch_command()[sql_parse.cc:1053]
00000001403584C3    mysqld.exe!do_command()[sql_parse.cc:724]
0000000140319FD6    mysqld.exe!handle_one_connection()[sql_connect.cc:1153]
00000001405603C5    mysqld.exe!pthread_start()[my_winthread.c:86]
00000001408F2635    mysqld.exe!_callthreadstart()[thread.c:295]
00000001408F2607    mysqld.exe!_threadstart()[thread.c:277]
00000000779FCDCD    kernel32.dll!BaseThreadInitThunk()
0000000077B4C6E1    ntdll.dll!RtlUserThreadStart()
Trying to get some variables.
Some pointers may be invalid and cause the dump to abort...
thd->query at 0000000004222F00=SELECT 1 FROM DUAL WHERE 1 = SOME (SELECT 1 FROM t1)
thd->thread_id=1
thd->killed=NOT_KILLED
[19 Jul 2008 13:00] Sergey Petrunya
Changed to a more precise synopsis.
[7 Sep 2008 22:21] Sergey Petrunya
The same issue as BUG#36896. Changing status to duplicate.