1、問題現象 create database syw_mtr; use syw_mtr; CREATE TABLE t1 (f1 VARCHAR(255) CHARACTER SET utf8)engine=tianmu; CREATE TABLE t2 AS SELECT LEFT(f1,171) ...
1、問題現象
create database syw_mtr;
use syw_mtr;
CREATE TABLE t1 (f1 VARCHAR(255) CHARACTER SET utf8)engine=tianmu;
CREATE TABLE t2 AS SELECT LEFT(f1,171) AS f2 FROM t1 UNION SELECT LEFT(f1,171) AS f2 FROM t1;
ERROR 2013 (HY000): Lost connection to MySQL server during query
問題issue:https://github.com/stoneatom/stonedb/issues/226
2、問題原因
bug代碼行
Query_result_create::prepare (sql_insert.cc:2753)
create_table->table不為空
assert(create_table->table == NULL);
stonedb堆棧
libc.so.6!raise (未知源:0)
libc.so.6!abort (未知源:0)
libc.so.6!__assert_fail_base (未知源:0)
libc.so.6!__assert_fail (未知源:0)
Query_result_create::prepare(Query_result_create * const this, List<Item> & values, SELECT_LEX_UNIT * u) (\opt\litaihong\stonedb\sql\sql_insert.cc:2753)
st_select_lex::prepare(st_select_lex * const this, THD * thd) (\opt\litaihong\stonedb\sql\sql_resolver.cc:361)
st_select_lex_unit::prepare_fake_select_lex(st_select_lex_unit * const this, THD * thd_arg) (\opt\litaihong\stonedb\sql\sql_union.cc:441)
st_select_lex_unit::optimize_for_stonedb(st_select_lex_unit * const this) (\opt\litaihong\stonedb\storage\stonedb\core\engine_execute.cpp:586)
stonedb::core::Engine::HandleSelect(stonedb::core::Engine * const this, THD * thd, LEX * lex, Query_result *& result, ulong setup_tables_done_option, int & res, int & optimize_after_sdb, int & sdb_free_join, int with_insert) (\opt\litaihong\stonedb\storage\stonedb\core\engine_execute.cpp:181)
stonedb::dbhandler::SDB_HandleSelect(THD * thd, LEX * lex, Query_result *& result, ulong setup_tables_done_option, int & res, int & optimize_after_sdb, int & sdb_free_join, int with_insert) (\opt\litaihong\stonedb\storage\stonedb\handler\ha_rcengine.cpp:82)
mysql_execute_command(THD * thd, bool first_level) (\opt\litaihong\stonedb\sql\sql_parse.cc:3265)
mysql_parse(THD * thd, Parser_state * parser_state) (\opt\litaihong\stonedb\sql\sql_parse.cc:5621)
dispatch_command(THD * thd, const COM_DATA * com_data, enum_server_command command) (\opt\litaihong\stonedb\sql\sql_parse.cc:1495)
do_command(THD * thd) (\opt\litaihong\stonedb\sql\sql_parse.cc:1034)
handle_connection(void * arg) (\opt\litaihong\stonedb\sql\conn_handler\connection_handler_per_thread.cc:313)
pfs_spawn_thread(void * arg) (\opt\litaihong\stonedb\storage\perfschema\pfs.cc:2197)
libpthread.so.0!start_thread (未知源:0)
libc.so.6!clone (未知源:0)
分析過程
assert(create_table->table == NULL);
Query_result_create::prepare (sql_insert.cc:2753)函數prepare階段和optimize階段在被調用了兩次
1、stonedb::core::Engine::HandleSelect函數首先調用
st_select_lex_unit::prepare->prepare_fake_select_lex ->Query_result_create::prepare
此時create_table->table 是NULL。
2、然後調用
st_select_lex_unit::optimize_for_stonedb -> prepare_fake_select_lex -> Query_result_create::prepare
此時create_table->table不為NULL,assert(create_table->table == NULL); 導致資料庫異常退出。
問題出現原因
分析st_select_lex_unit::optimize_for_stonedb函數發現是來源於MySQL的st_select_lex_unit::exec()函數
3、解決辦法
mysql的handle_query函數先有prepare然後是optimize函數,但我們stonedb的optimize函數是根據MySQL的st_select_lex_unit::exec()寫的,不知道為啥沒有正常的optimize流程
兩種解決方案:
1、修改拋異常的代碼行Query_result_create::prepare (sql_insert.cc:2753)函數
assert(create_table->table == NULL);
2、重寫stonedb的st_select_lex_unit::optimize_for_stonedb函數,改動比較大,涉及功能多。
解決方案更新:
A:我們發現,這個問題是由於在優化器的代碼中,Lex unit 兩次prepare造成的。
首先我們拋棄了對assert語句修改的考慮,因為那裡判斷表沒有創建是合理的。
於是解決方案有兩種,
1:考慮在lex unit 的prepare裡加入 is_prepared的判斷。但這個方案,影響面很大,因為這個函數所有的語法都會影響到。
2:針對,select union 或者 select join,以及他們出現的複雜的組合做修改。發現了三處異常點需要進行is_prepared判斷。1:union處。2:join處。3:fake_lex_prepare處。
B:針對我們的修改添加了相應mtr語句進行覆蓋。一併記錄在issue226中。
https://github.com/stoneatom/stonedb/issues/226
ADD test cases to cover these ctas queries for the following reason.
1: From code perspective. There are enough evidences that we want to support these ctas.
2: Our fix can cover these related queries.
CREATE TABLE t2 AS SELECT LEFT(f1,171) AS f2 FROM t1 UNION SELECT LEFT(f1,171) AS f2 FROM t1;
CREATE TABLE t3 AS SELECT t1.f1 AS f3 FROM t1 LEFT JOIN t2 ON t1.f1 = t2.f2;
CREATE TABLE t4 AS SELECT t1.f1 AS f4 FROM t1 INNER JOIN t2 ON t1.f1 = t2.f2;
CREATE TABLE t5 AS SELECT t1.f1 AS f5 FROM t1 RIGHT JOIN t2 ON t1.f1 = t2.f2;
CREATE TABLE t6 AS SELECT t1.f1 AS f6 FROM t1 UNION SELECT t2.f2 AS f6 FROM t2 LEFT JOIN t3 ON t2.f2 = t3.f3;
CREATE TABLE t7 AS SELECT t1.f1 AS f7 FROM t1 UNION SELECT t2.f2 AS f7 FROM t2 INNER JOIN t3 ON t2.f2 = t3.f3;
CREATE TABLE t8 AS SELECT t1.f1 AS f8 FROM t1 UNION SELECT t2.f2 AS f8 FROM t2 RIGHT JOIN t3 ON t2.f2 = t3.f3;
CREATE TABLE t9 AS SELECT t1.f1 AS f9 FROM t1 INNER JOIN t3 ON t1.f1 = t3.f3 UNION SELECT t2.f2 AS f9 FROM t2;
4、MySQL正常流程堆棧
Query_result_create::prepare(Query_result_create * const this, List<Item> & values, SELECT_LEX_UNIT * u) (\opt\litaihong\stonedb\sql\sql_insert.cc:2750)
st_select_lex::prepare(st_select_lex * const this, THD * thd) (\opt\litaihong\stonedb\sql\sql_resolver.cc:361)
st_select_lex_unit::prepare_fake_select_lex(st_select_lex_unit * const this, THD * thd_arg) (\opt\litaihong\stonedb\sql\sql_union.cc:441)
st_select_lex_unit::prepare(st_select_lex_unit * const this, THD * thd_arg, Query_result * sel_result, ulonglong added_options, ulonglong removed_options) (\opt\litaihong\stonedb\sql\sql_union.cc:670)
handle_query(THD * thd, LEX * lex, Query_result * result, ulonglong added_options, ulonglong removed_options, int optimize_after_bh, int free_join_from_bh) (\opt\litaihong\stonedb\sql\sql_select.cc:150)
mysql_execute_command(THD * thd, bool first_level) (\opt\litaihong\stonedb\sql\sql_parse.cc:3266)
mysql_parse(THD * thd, Parser_state * parser_state) (\opt\litaihong\stonedb\sql\sql_parse.cc:5621)
dispatch_command(THD * thd, const COM_DATA * com_data, enum_server_command command) (\opt\litaihong\stonedb\sql\sql_parse.cc:1495)
do_command(THD * thd) (\opt\litaihong\stonedb\sql\sql_parse.cc:1034)
handle_connection(void * arg) (\opt\litaihong\stonedb\sql\conn_handler\connection_handler_per_thread.cc:313)
pfs_spawn_thread(void * arg) (\opt\litaihong\stonedb\storage\perfschema\pfs.cc:2197)
libpthread.so.0!start_thread (未知源:0)
libc.so.6!clone (未知源:0)