【StoneDB研发日志】union功能bug记录

打印 上一主题 下一主题

主题 812|帖子 812|积分 2436

1、问题现象
  1. create database syw_mtr;
  2. use syw_mtr;
  3. CREATE TABLE t1 (f1 VARCHAR(255) CHARACTER SET utf8)engine=tianmu;
  4. CREATE TABLE t2 AS SELECT LEFT(f1,171) AS f2 FROM t1 UNION SELECT LEFT(f1,171) AS f2 FROM t1;
  5. 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不为空
  1. assert(create_table->table == NULL);
复制代码
stonedb堆栈
  1.     libc.so.6!raise (未知源:0)
  2.     libc.so.6!abort (未知源:0)
  3.     libc.so.6!__assert_fail_base (未知源:0)
  4.     libc.so.6!__assert_fail (未知源:0)
  5.     Query_result_create::prepare(Query_result_create * const this, List<Item> & values, SELECT_LEX_UNIT * u) (\opt\litaihong\stonedb\sql\sql_insert.cc:2753)
  6.     st_select_lex::prepare(st_select_lex * const this, THD * thd) (\opt\litaihong\stonedb\sql\sql_resolver.cc:361)
  7.     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)
  8.     st_select_lex_unit::optimize_for_stonedb(st_select_lex_unit * const this) (\opt\litaihong\stonedb\storage\stonedb\core\engine_execute.cpp:586)
  9.     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)
  10.     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)
  11.     mysql_execute_command(THD * thd, bool first_level) (\opt\litaihong\stonedb\sql\sql_parse.cc:3265)
  12.     mysql_parse(THD * thd, Parser_state * parser_state) (\opt\litaihong\stonedb\sql\sql_parse.cc:5621)
  13.     dispatch_command(THD * thd, const COM_DATA * com_data, enum_server_command command) (\opt\litaihong\stonedb\sql\sql_parse.cc:1495)
  14.     do_command(THD * thd) (\opt\litaihong\stonedb\sql\sql_parse.cc:1034)
  15.     handle_connection(void * arg) (\opt\litaihong\stonedb\sql\conn_handler\connection_handler_per_thread.cc:313)
  16.     pfs_spawn_thread(void * arg) (\opt\litaihong\stonedb\storage\perfschema\pfs.cc:2197)
  17.     libpthread.so.0!start_thread (未知源:0)
  18.     libc.so.6!clone (未知源:0)
复制代码
分析过程
  1. 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正常流程堆栈
  1. Query_result_create::prepare(Query_result_create * const this, List<Item> & values, SELECT_LEX_UNIT * u) (\opt\litaihong\stonedb\sql\sql_insert.cc:2750)
  2. st_select_lex::prepare(st_select_lex * const this, THD * thd) (\opt\litaihong\stonedb\sql\sql_resolver.cc:361)
  3. 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)
  4. 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)
  5. 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)
  6. mysql_execute_command(THD * thd, bool first_level) (\opt\litaihong\stonedb\sql\sql_parse.cc:3266)
  7. mysql_parse(THD * thd, Parser_state * parser_state) (\opt\litaihong\stonedb\sql\sql_parse.cc:5621)
  8. dispatch_command(THD * thd, const COM_DATA * com_data, enum_server_command command) (\opt\litaihong\stonedb\sql\sql_parse.cc:1495)
  9. do_command(THD * thd) (\opt\litaihong\stonedb\sql\sql_parse.cc:1034)
  10. handle_connection(void * arg) (\opt\litaihong\stonedb\sql\conn_handler\connection_handler_per_thread.cc:313)
  11. pfs_spawn_thread(void * arg) (\opt\litaihong\stonedb\storage\perfschema\pfs.cc:2197)
  12. libpthread.so.0!start_thread (未知源:0)
  13. libc.so.6!clone (未知源:0)
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

怀念夏天

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表