stoneatom / stonedb

StoneDB is an Open-Source MySQL HTAP and MySQL-Native DataBase for OLTP, Real-Time Analytics, a counterpart of MySQLHeatWave. (https://stonedb.io)
https://stonedb.io/
GNU General Public License v2.0
862 stars 139 forks source link

bug: ERROR 6 (HY000), The WHERE XOR clause that is not supported #769

Open davidshiz opened 1 year ago

davidshiz commented 1 year ago

Have you read the Contributing Guidelines on issues?

Please confirm if bug report does NOT exists already ?

Describe the problem

mysql> create table tt (val double);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into tt values (1.2345);
Query OK, 1 row affected (0.00 sec)

mysql> select 1 from (select * from tt) as A join tt where A.val > 1 XOR tt.val > 2;
ERROR 6 (HY000): The query includes syntax that is not supported by the storage engine. Either restructure the query with supported syntax, or enable the MySQL core::Query Path in config file to execute the query with reduced performance.

Expected behavior

mysql> select 1 from (select * from tt) as A join tt where A.val > 1 XOR tt.val > 2; +---+ | 1 | +---+ | 1 | +---+ 1 row in set (0.00 sec)

How To Reproduce

create table tt (val double);
insert into tt values (1.2345);
select 1 from (select * from tt) as A join tt where A.val > 1 XOR tt.val > 2;

Environment

ubuntu@ubuntu:~$ cat /etc/os-release NAME="Ubuntu" VERSION="20.04.4 LTS (Focal Fossa)" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 20.04.4 LTS" VERSION_ID="20.04"

ubuntu@ubuntu:~$ /stonedb57/install/bin/mysqld --version /stonedb57/install/bin/mysqld Ver 5.7.36-StoneDB for Linux on x86_64 (build-) build information as follow: Repository address: https://github.com/stoneatom/stonedb.git:stonedb-5.7-dev Branch name: stonedb-5.7-dev Last commit ID: https://github.com/stoneatom/stonedb/commit/5d996f9355b5241eaa54f3e4b652a60c9c229b0e Last commit time: Date: Sat Oct 8 14:34:42 2022 +0800 Build time: Date: Fri 14 Oct 2022 12:28:00 PM UTC

Are you interested in submitting a PR to solve the problem?

isredstar commented 1 year ago

ACK

adofsauron commented 1 year ago

ACK

adofsauron commented 1 year ago

mysql5.7 Logical Operators documentation Reference

https://dev.mysql.com/doc/refman/5.7/en/logical-operators.html#operator_xor

adofsauron commented 1 year ago

Lack of support for XOR logical operation predicates


  enum class StepType {
    TABLE_ALIAS,
    TMP_TABLE,
    CREATE_CONDS,
    AND_F,
    OR_F,
    AND_DESC,
    OR_DESC,
    T_MODE,
    JOIN_T,
    LEFT_JOIN_ON,
    INNER_JOIN_ON,
    ADD_CONDS,
    APPLY_CONDS,
    ADD_COLUMN,
    ADD_ORDER,
    UNION,
    RESULT,
    STEP_ERROR,
    CREATE_VC
  };
adofsauron commented 1 year ago

Compare the processing stack for the OR predicate


(gdb) bt
#0  Tianmu::core::CompiledQuery::Or (this=0x7fb692328730, c1=..., t=..., e1=..., pr=Tianmu::common::Operator::O_MORE, e2=..., e3=...)
    at /root/work/stonedb-dev-20230116/storage/tianmu/core/compiled_query.cpp:520
#1  0x0000000002cb2b9c in Tianmu::core::Query::ConditionNumberFromComparison (this=0x7fb692328800, conds=0x7fb3eca679a0, tmp_table=..., filter_type=Tianmu::core::CondType::WHERE_COND, 
    and_me_filter=0x7fb3eca0cf20, is_or_subtree=true, negative=false, can_cond_push=false) at /root/work/stonedb-dev-20230116/storage/tianmu/core/query.cpp:1355
#2  0x0000000002cb4bf4 in Tianmu::core::Query::ConditionNumber (this=0x7fb692328800, conds=0x7fb3eca679a0, tmp_table=..., filter_type=Tianmu::core::CondType::WHERE_COND, 
    and_me_filter=0x7fb3eca0cf20, is_or_subtree=true, can_cond_push=false) at /root/work/stonedb-dev-20230116/storage/tianmu/core/query.cpp:1575
#3  0x0000000002cb3c41 in Tianmu::core::Query::ConditionNumber (this=0x7fb692328800, conds=0x7fb3ec0e0398, tmp_table=..., filter_type=Tianmu::core::CondType::WHERE_COND, and_me_filter=0x0, 
    is_or_subtree=false, can_cond_push=false) at /root/work/stonedb-dev-20230116/storage/tianmu/core/query.cpp:1481
#4  0x0000000002cb5636 in Tianmu::core::Query::BuildConditions (this=0x7fb692328800, conds=0x7fb3ec0e0398, cond_id=..., cq=0x7fb692328730, tmp_table=..., 
    filter_type=Tianmu::core::CondType::WHERE_COND, is_zero_result=false, join_type=Tianmu::core::JoinType::JO_INNER, can_cond_push=false)
    at /root/work/stonedb-dev-20230116/storage/tianmu/core/query.cpp:1623
#5  0x0000000002cd4276 in Tianmu::core::Query::Compile (this=0x7fb692328800, compiled_query=0x7fb692328730, selects_list=0x7fb3ec0def60, last_distinct=0x0, res_tab=0x0, ignore_limit=false, 
    left_expr_for_subselect=0x0, oper_for_subselect=0x0, ignore_minmax=false, for_subq_in_where=false) at /root/work/stonedb-dev-20230116/storage/tianmu/core/query_compile.cpp:1122
#6  0x0000000002c8026b in Tianmu::core::Engine::Execute (this=0x53dcfd0, thd=0x7fb3ec0db740, lex=0x7fb3ec0dda68, result_output=0x7fb3ec0eee20, unit_for_union=0x0)
    at /root/work/stonedb-dev-20230116/storage/tianmu/core/engine_execute.cpp:436
#7  0x0000000002c7f5a2 in Tianmu::core::Engine::HandleSelect (this=0x53dcfd0, thd=0x7fb3ec0db740, lex=0x7fb3ec0dda68, result=@0x7fb692328dc8: 0x7fb3ec0eee20, setup_tables_done_option=0, 
    res=@0x7fb692328dc4: 0, optimize_after_tianmu=@0x7fb692328dbc: 1, tianmu_free_join=@0x7fb692328dc0: 1, with_insert=0)
    at /root/work/stonedb-dev-20230116/storage/tianmu/core/engine_execute.cpp:238
#8  0x0000000002d839fd in Tianmu::handler::ha_my_tianmu_query (thd=0x7fb3ec0db740, lex=0x7fb3ec0dda68, result_output=@0x7fb692328dc8: 0x7fb3ec0eee20, setup_tables_done_option=0, 
    res=@0x7fb692328dc4: 0, optimize_after_tianmu=@0x7fb692328dbc: 1, tianmu_free_join=@0x7fb692328dc0: 1, with_insert=0)
    at /root/work/stonedb-dev-20230116/storage/tianmu/handler/ha_my_tianmu.cpp:88
#9  0x00000000023c0859 in execute_sqlcom_select (thd=0x7fb3ec0db740, all_tables=0x7fb3ec0ee310) at /root/work/stonedb-dev-20230116/sql/sql_parse.cc:5208
#10 0x00000000023b9bcf in mysql_execute_command (thd=0x7fb3ec0db740, first_level=true) at /root/work/stonedb-dev-20230116/sql/sql_parse.cc:2851
#11 0x00000000023c18bf in mysql_parse (thd=0x7fb3ec0db740, parser_state=0x7fb692329f90) at /root/work/stonedb-dev-20230116/sql/sql_parse.cc:5646
#12 0x00000000023b68a8 in dispatch_command (thd=0x7fb3ec0db740, com_data=0x7fb69232a730, command=COM_QUERY) at /root/work/stonedb-dev-20230116/sql/sql_parse.cc:1495
#13 0x00000000023b56e9 in do_command (thd=0x7fb3ec0db740) at /root/work/stonedb-dev-20230116/sql/sql_parse.cc:1034
#14 0x00000000024e6ebf in handle_connection (arg=0x901a5c0) at /root/work/stonedb-dev-20230116/sql/conn_handler/connection_handler_per_thread.cc:313
#15 0x0000000002bb6cd8 in pfs_spawn_thread (arg=0x8e71990) at /root/work/stonedb-dev-20230116/storage/perfschema/pfs.cc:2197
#16 0x00007fb6e1ce41ca in start_thread () from /lib64/libpthread.so.0
#17 0x00007fb6dec3ce73 in clone () from /lib64/libc.so.6
adofsauron commented 1 year ago

Code with disabled XOR predicate functionality

FDDDA125-45ED-4550-9727-4DE981A7FAFE

00843CCC-07B2-4b13-8391-E759D397C161

adofsauron commented 1 year ago

Call stack


(gdb) bt
#0  Tianmu::core::Query::ConditionNumber (this=0x7fb692328800, conds=0x7fb3ec0e0398, tmp_table=..., filter_type=Tianmu::core::CondType::WHERE_COND, and_me_filter=0x0, is_or_subtree=false, 
    can_cond_push=false) at /root/work/stonedb-dev-20230116/storage/tianmu/core/query.cpp:1571
#1  0x0000000002cb5636 in Tianmu::core::Query::BuildConditions (this=0x7fb692328800, conds=0x7fb3ec0e0398, cond_id=..., cq=0x7fb692328730, tmp_table=..., 
    filter_type=Tianmu::core::CondType::WHERE_COND, is_zero_result=false, join_type=Tianmu::core::JoinType::JO_INNER, can_cond_push=false)
    at /root/work/stonedb-dev-20230116/storage/tianmu/core/query.cpp:1623
#2  0x0000000002cd4276 in Tianmu::core::Query::Compile (this=0x7fb692328800, compiled_query=0x7fb692328730, selects_list=0x7fb3ec0def60, last_distinct=0x0, res_tab=0x0, ignore_limit=false, 
    left_expr_for_subselect=0x0, oper_for_subselect=0x0, ignore_minmax=false, for_subq_in_where=false) at /root/work/stonedb-dev-20230116/storage/tianmu/core/query_compile.cpp:1122
#3  0x0000000002c8026b in Tianmu::core::Engine::Execute (this=0x53dcfd0, thd=0x7fb3ec0db740, lex=0x7fb3ec0dda68, result_output=0x7fb3ec0eee70, unit_for_union=0x0)
    at /root/work/stonedb-dev-20230116/storage/tianmu/core/engine_execute.cpp:436
#4  0x0000000002c7f5a2 in Tianmu::core::Engine::HandleSelect (this=0x53dcfd0, thd=0x7fb3ec0db740, lex=0x7fb3ec0dda68, result=@0x7fb692328dc8: 0x7fb3ec0eee70, setup_tables_done_option=0, 
    res=@0x7fb692328dc4: 0, optimize_after_tianmu=@0x7fb692328dbc: 1, tianmu_free_join=@0x7fb692328dc0: 1, with_insert=0)
    at /root/work/stonedb-dev-20230116/storage/tianmu/core/engine_execute.cpp:238
#5  0x0000000002d839fd in Tianmu::handler::ha_my_tianmu_query (thd=0x7fb3ec0db740, lex=0x7fb3ec0dda68, result_output=@0x7fb692328dc8: 0x7fb3ec0eee70, setup_tables_done_option=0, 
    res=@0x7fb692328dc4: 0, optimize_after_tianmu=@0x7fb692328dbc: 1, tianmu_free_join=@0x7fb692328dc0: 1, with_insert=0)
    at /root/work/stonedb-dev-20230116/storage/tianmu/handler/ha_my_tianmu.cpp:88
#6  0x00000000023c0859 in execute_sqlcom_select (thd=0x7fb3ec0db740, all_tables=0x7fb3ec0ee310) at /root/work/stonedb-dev-20230116/sql/sql_parse.cc:5208
#7  0x00000000023b9bcf in mysql_execute_command (thd=0x7fb3ec0db740, first_level=true) at /root/work/stonedb-dev-20230116/sql/sql_parse.cc:2851
#8  0x00000000023c18bf in mysql_parse (thd=0x7fb3ec0db740, parser_state=0x7fb692329f90) at /root/work/stonedb-dev-20230116/sql/sql_parse.cc:5646
#9  0x00000000023b68a8 in dispatch_command (thd=0x7fb3ec0db740, com_data=0x7fb69232a730, command=COM_QUERY) at /root/work/stonedb-dev-20230116/sql/sql_parse.cc:1495
#10 0x00000000023b56e9 in do_command (thd=0x7fb3ec0db740) at /root/work/stonedb-dev-20230116/sql/sql_parse.cc:1034
#11 0x00000000024e6ebf in handle_connection (arg=0x901a5c0) at /root/work/stonedb-dev-20230116/sql/conn_handler/connection_handler_per_thread.cc:313
#12 0x0000000002bb6cd8 in pfs_spawn_thread (arg=0x8e71990) at /root/work/stonedb-dev-20230116/storage/perfschema/pfs.cc:2197
#13 0x00007fb6e1ce41ca in start_thread () from /lib64/libpthread.so.0
#14 0x00007fb6dec3ce73 in clone () from /lib64/libc.so.6
adofsauron commented 1 year ago

The query tree transformation code is a bit complex and needs to be analyzed carefully


(gdb) bt
#0  Tianmu::core::Query::Preexecute (this=this@entry=0x7f76ba34ae20, qu=..., sender=sender@entry=0x7f73d44a1d70, display_now=display_now@entry=true)
    at /root/work/stonedb-dev-20230207/storage/tianmu/core/query.cpp:572
#1  0x00000000014aa681 in Tianmu::core::Engine::Execute (this=<optimized out>, thd=0x7f7414c654b0, lex=0x7f7414c67628, result_output=0x7f7414a063d8, unit_for_union=<optimized out>)
    at /root/work/stonedb-dev-20230207/storage/tianmu/core/engine_execute.cpp:477
#2  0x00000000014abaaa in Tianmu::core::Engine::HandleSelect (this=<optimized out>, thd=thd@entry=0x7f7414c654b0, lex=lex@entry=0x7f7414c67628, result=@0x7f76ba34b1d8: 0x7f7414a063d8, 
    setup_tables_done_option=setup_tables_done_option@entry=0, res=@0x7f76ba34b1cc: 32628, optimize_after_tianmu=<optimized out>, tianmu_free_join=<optimized out>, 
    with_insert=<optimized out>) at /root/work/stonedb-dev-20230207/storage/tianmu/core/engine_execute.cpp:238
#3  0x0000000001532365 in Tianmu::handler::ha_my_tianmu_query (thd=thd@entry=0x7f7414c654b0, lex=lex@entry=0x7f7414c67628, result_output=@0x7f76ba34b1d8: 0x7f7414a063d8, 
    setup_tables_done_option=setup_tables_done_option@entry=0, res=@0x7f76ba34b1cc: 32628, optimize_after_tianmu=@0x7f76ba34b1d4: 1, tianmu_free_join=@0x7f76ba34b1d0: 1, with_insert=0)
    at /root/work/stonedb-dev-20230207/storage/tianmu/handler/ha_my_tianmu.cpp:88
#4  0x0000000000eb44ae in execute_sqlcom_select (thd=thd@entry=0x7f7414c654b0, all_tables=<optimized out>) at /root/work/stonedb-dev-20230207/sql/sql_parse.cc:4874
#5  0x0000000000ebbac8 in mysql_execute_command (thd=0x7f7414c654b0, first_level=<optimized out>) at /root/work/stonedb-dev-20230207/sql/sql_parse.cc:2675
#6  0x0000000000ebdf3d in mysql_parse (thd=thd@entry=0x7f7414c654b0, parser_state=parser_state@entry=0x7f76ba34c0c0) at /root/work/stonedb-dev-20230207/sql/sql_parse.cc:5279
#7  0x0000000000ebf23c in dispatch_command (thd=0x7f7414c654b0, com_data=<optimized out>, command=COM_QUERY) at /root/work/stonedb-dev-20230207/sql/sql_parse.cc:1399
#8  0x0000000000ec03f7 in do_command (thd=thd@entry=0x7f7414c654b0) at /root/work/stonedb-dev-20230207/sql/sql_parse.cc:976
#9  0x0000000000f78c58 in handle_connection (arg=arg@entry=0x7081d60) at /root/work/stonedb-dev-20230207/sql/conn_handler/connection_handler_per_thread.cc:313
#10 0x00000000014265e7 in pfs_spawn_thread (arg=0x6afef10) at /root/work/stonedb-dev-20230207/storage/perfschema/pfs.cc:2197
#11 0x00007f7708fad1ca in start_thread () from /lib64/libpthread.so.0
#12 0x00007f7705f05e73 in clone () from /lib64/libc.so.6

TempTable *Query::Preexecute(CompiledQuery &qu, ResultSender *sender, [[maybe_unused]] bool display_now) {
  if (TIANMU_LOGCHECK(LogCtl_Level::DEBUG)) {
    qu.Print(this);
  }
  std::vector<Condition *> conds(qu.NumOfConds());

  TempTable *output_table = nullptr;  // NOTE: this pointer will be returned by the function

  ta.resize(qu.NumOfTabs());
  auto global_limits = qu.GetGlobalLimit();

  cq = &qu;
  // Execution itself
  for (int i = 0; i < qu.NumOfSteps(); i++) {
    CompiledQuery::CQStep step = qu.Step(i);
    std::shared_ptr<JustATable> t1_ptr, t2_ptr, t3_ptr;

    if (step.t1.n != common::NULL_VALUE_32) {
      if (step.t1.n >= 0)
        t1_ptr = Table(step.t1.n);  // normal table
      else {
        t1_ptr = ta[-step.t1.n - 1];  // TempTable
      }
    }
    if (step.t2.n != common::NULL_VALUE_32) {
      if (step.t2.n >= 0)
        t2_ptr = Table(step.t2.n);  // normal table
      else {
        t2_ptr = ta[-step.t2.n - 1];  // TempTable
      }
    }
    if (step.t3.n != common::NULL_VALUE_32) {
      if (step.t3.n >= 0)
        t3_ptr = Table(step.t3.n);  // normal table
      else {
        t3_ptr = ta[-step.t3.n - 1];  // TempTable
      }
    }
    // Some technical information
    if (step.alias && std::strcmp(step.alias, "roughstats") == 0) {
      // magical word (passed as table alias) to display statistics
      ((TempTable *)ta[-step.t1.n - 1].get())->DisplayRSI();
    }

    if (step.alias && std::strcmp(step.alias, "roughattrstats") == 0) {
      // magical word (passed as table alias) to display attr. statistics
      m_conn->SetDisplayAttrStats();
    }

    // Implementation of steps
    try {
      switch (step.type) {
        case CompiledQuery::StepType::TABLE_ALIAS:
          ta[-step.t1.n - 1] = t2_ptr;
          break;
        case CompiledQuery::StepType::TMP_TABLE:
          DEBUG_ASSERT(step.t1.n < 0);
          ta[-step.t1.n - 1] = step.n1
                                   ? TempTable::Create(ta[-step.tables1[0].n - 1].get(), step.tables1[0].n, this, true)
                                   : TempTable::Create(ta[-step.tables1[0].n - 1].get(), step.tables1[0].n, this);
          ((TempTable *)ta[-step.t1.n - 1].get())->ReserveVirtColumns(qu.NumOfVirtualColumns(step.t1));
          break;
        case CompiledQuery::StepType::CREATE_CONDS:
          DEBUG_ASSERT(step.t1.n < 0);
          if (step.ex_op == common::ExtraOperation::EX_COND_PUSH) {
            ((TempTable *)ta[-step.t1.n - 1].get())->MarkCondPush();
          }
          step.e1.vc = (step.e1.vc_id != common::NULL_VALUE_32)
                           ? ((TempTable *)ta[-step.t1.n - 1].get())->GetVirtualColumn(step.e1.vc_id)
                           : nullptr;
          step.e2.vc = (step.e2.vc_id != common::NULL_VALUE_32)
                           ? ((TempTable *)ta[-step.t1.n - 1].get())->GetVirtualColumn(step.e2.vc_id)
                           : nullptr;
          step.e3.vc = (step.e3.vc_id != common::NULL_VALUE_32)
                           ? ((TempTable *)ta[-step.t1.n - 1].get())->GetVirtualColumn(step.e3.vc_id)
                           : nullptr;
          if (step.n1 != static_cast<int64_t>(CondType::OR_SUBTREE)) {  // on result = false
            conds[step.c1.n] = new Condition();
            if (step.c2.IsNull()) {
              conds[step.c1.n]->AddDescriptor(
                  step.e1, step.op, step.e2, step.e3, (TempTable *)ta[-step.t1.n - 1].get(), qu.GetNumOfDimens(step.t1),
                  (step.op == common::Operator::O_LIKE || step.op == common::Operator::O_NOT_LIKE) ? char(step.n2)
                                                                                                   : '\\');
            } else {
              DEBUG_ASSERT(conds[step.c2.n]->IsType_Tree());
              conds[step.c1.n]->AddDescriptor(static_cast<SingleTreeCondition *>(conds[step.c2.n])->GetTree(),
                                              (TempTable *)ta[-step.t1.n - 1].get(), qu.GetNumOfDimens(step.t1));
            }
          } else {  // on result = true
            if (step.c2.IsNull())
              conds[step.c1.n] =
                  new SingleTreeCondition(step.e1, step.op, step.e2, step.e3, (TempTable *)ta[-step.t1.n - 1].get(),
                                          qu.GetNumOfDimens(step.t1), char(step.n2));
            else {
              DEBUG_ASSERT(conds[step.c2.n]->IsType_Tree());
              conds[step.c1.n] = new Condition();
              conds[step.c1.n]->AddDescriptor(((SingleTreeCondition *)conds[step.c2.n])->GetTree(),
                                              (TempTable *)ta[-step.t1.n - 1].get(), qu.GetNumOfDimens(step.t1));
            }
          }
          break;
        case CompiledQuery::StepType::AND_F:
        case CompiledQuery::StepType::OR_F:
          if (!conds[step.c2.n]->IsType_Tree()) {
            ASSERT(step.type == CompiledQuery::StepType::AND_F);
            auto cond2 = conds[step.c2.n];
            for (size_t i = 0; i < cond2->Size(); i++) {
              auto &desc = (*cond2)[i];
              if (conds[step.c1.n]->IsType_Tree()) {
                TempTable *temptb = (TempTable *)ta[-qu.GetTableOfCond(step.c2).n - 1].get();
                int no_dims = qu.GetNumOfDimens(qu.GetTableOfCond(step.c2));
                if (desc.op == common::Operator::O_OR_TREE) {
                  static_cast<SingleTreeCondition *>(conds[step.c1.n])
                      ->AddTree(common::LogicalOperator::O_AND, desc.tree, no_dims);
                } else {
                  static_cast<SingleTreeCondition *>(conds[step.c1.n])
                      ->AddDescriptor(common::LogicalOperator::O_AND, desc.attr, desc.op, desc.val1, desc.val2, temptb,
                                      no_dims, desc.like_esc);
                }
              } else {
                conds[step.c1.n]->AddDescriptor(desc);
              }
            }
          } else if (conds[step.c1.n]->IsType_Tree()) {  // on result = false
            DEBUG_ASSERT(conds[step.c2.n]->IsType_Tree());
            common::LogicalOperator lop = (step.type == CompiledQuery::StepType::AND_F ? common::LogicalOperator::O_AND
                                                                                       : common::LogicalOperator::O_OR);
            static_cast<SingleTreeCondition *>(conds[step.c1.n])
                ->AddTree(lop, static_cast<SingleTreeCondition *>(conds[step.c2.n])->GetTree(),
                          qu.GetNumOfDimens(step.t1));
          } else {
            DEBUG_ASSERT(conds[step.c2.n]->IsType_Tree());
            conds[step.c1.n]->AddDescriptor(static_cast<SingleTreeCondition *>(conds[step.c2.n])->GetTree(),
                                            (TempTable *)ta[-qu.GetTableOfCond(step.c1).n - 1].get(),
                                            qu.GetNumOfDimens(qu.GetTableOfCond(step.c1)));
          }
          break;
        case CompiledQuery::StepType::OR_DESC:
        case CompiledQuery::StepType::AND_DESC: {
          common::LogicalOperator lop =
              (step.type == CompiledQuery::StepType::AND_DESC ? common::LogicalOperator::O_AND
                                                              : common::LogicalOperator::O_OR);
          step.e1.vc = (step.e1.vc_id != common::NULL_VALUE_32)
                           ? ((TempTable *)ta[-step.t1.n - 1].get())->GetVirtualColumn(step.e1.vc_id)
                           : nullptr;
          step.e2.vc = (step.e2.vc_id != common::NULL_VALUE_32)
                           ? ((TempTable *)ta[-step.t1.n - 1].get())->GetVirtualColumn(step.e2.vc_id)
                           : nullptr;
          step.e3.vc = (step.e3.vc_id != common::NULL_VALUE_32)
                           ? ((TempTable *)ta[-step.t1.n - 1].get())->GetVirtualColumn(step.e3.vc_id)
                           : nullptr;
          if (!conds[step.c1.n]->IsType_Tree()) {
            DEBUG_ASSERT(conds[step.c1.n]);
            conds[step.c1.n]->AddDescriptor(
                step.e1, step.op, step.e2, step.e3, (TempTable *)ta[-step.t1.n - 1].get(), qu.GetNumOfDimens(step.t1),
                (step.op == common::Operator::O_LIKE || step.op == common::Operator::O_NOT_LIKE) ? char(step.n2)
                                                                                                 : '\\');
          } else
            static_cast<SingleTreeCondition *>(conds[step.c1.n])
                ->AddDescriptor(lop, step.e1, step.op, step.e2, step.e3, (TempTable *)ta[-step.t1.n - 1].get(),
                                qu.GetNumOfDimens(step.t1),
                                (step.op == common::Operator::O_LIKE || step.op == common::Operator::O_NOT_LIKE)
                                    ? char(step.n2)
                                    : '\\');
          break;
        }
        case CompiledQuery::StepType::T_MODE:
          DEBUG_ASSERT(step.t1.n < 0 && ta[-step.t1.n - 1]->TableType() == TType::TEMP_TABLE);
          ((TempTable *)ta[-step.t1.n - 1].get())->SetMode(step.tmpar, step.n1, step.n2);
          break;
        case CompiledQuery::StepType::JOIN_T:
          DEBUG_ASSERT(step.t1.n < 0 && ta[-step.t1.n - 1]->TableType() == TType::TEMP_TABLE);
          ((TempTable *)ta[-step.t1.n - 1].get())->JoinT(t2_ptr.get(), step.t2.n, step.jt);
          break;
        case CompiledQuery::StepType::ADD_CONDS: {
          DEBUG_ASSERT(step.t1.n < 0 && ta[-step.t1.n - 1]->TableType() == TType::TEMP_TABLE);
          if (step.c1.n == common::NULL_VALUE_32)
            break;
          if (step.n1 != static_cast<int64_t>(CondType::HAVING_COND))
            conds[step.c1.n]->Simplify();
          ((TempTable *)ta[-step.t1.n - 1].get())->AddConds(conds[step.c1.n], (CondType)step.n1);
          break;
        }
        case CompiledQuery::StepType::LEFT_JOIN_ON: {
          DEBUG_ASSERT(step.t1.n < 0 && ta[-step.t1.n - 1]->TableType() == TType::TEMP_TABLE);
          if (step.c1.n == common::NULL_VALUE_32)
            break;
          ((TempTable *)ta[-step.t1.n - 1].get())->AddLeftConds(conds[step.c1.n], step.tables1, step.tables2);
          break;
        }
        case CompiledQuery::StepType::INNER_JOIN_ON: {
          DEBUG_ASSERT(step.t1.n < 0 && ta[-step.t1.n - 1]->TableType() == TType::TEMP_TABLE);
          if (step.c1.n == common::NULL_VALUE_32)
            break;
          ((TempTable *)ta[-step.t1.n - 1].get())->AddInnerConds(conds[step.c1.n], step.tables1);
          break;
        }
        case CompiledQuery::StepType::APPLY_CONDS: {
          int64_t cur_limit = -1;
          auto *tb = (TempTable *)ta[-step.t1.n - 1].get();

          if (qu.FindDistinct(step.t1.n))
            tb->SetMode(TMParameter::TM_DISTINCT, 0, 0);
          if (qu.NoAggregationOrderingAndDistinct(step.t1.n))
            cur_limit = qu.FindLimit(step.t1.n);

          ParameterizedFilter *filter = tb->GetFilterP();

          if (cur_limit != -1 && filter->NoParameterizedDescs())
            cur_limit = -1;

          std::set<int> used_dims = qu.GetUsedDims(step.t1, ta);

          // no need any more to check WHERE for not used dims
          bool is_simple_filter = true;  // qu.IsSimpleFilter(step.c1);
          if (used_dims.size() == 1 && used_dims.find(common::NULL_VALUE_32) != used_dims.end())
            is_simple_filter = false;
          for (int i = 0; i < filter->mind_->NumOfDimensions(); i++) {
            (used_dims.find(i) == used_dims.end() && is_simple_filter && (!tb->CanCondPushDown()))
                ? filter->mind_->ResetUsedInOutput(i)
                : filter->mind_->SetUsedInOutput(i);
          }

          if (IsRoughQuery()) {
            filter->RoughUpdateParamFilter();
          } else
            filter->UpdateMultiIndex(qu.CountColumnOnly(step.t1), cur_limit);
          break;
        }
        case CompiledQuery::StepType::ADD_COLUMN: {
          DEBUG_ASSERT(step.t1.n < 0 && ta[-step.t1.n - 1]->TableType() == TType::TEMP_TABLE);
          CQTerm e(step.e1);
          if (e.vc_id != common::NULL_VALUE_32)
            e.vc =
                ((TempTable *)ta[-step.t1.n - 1].get())->GetVirtualColumn(step.e1.vc_id);  // vc must have been created
          step.a1.n = ((TempTable *)ta[-step.t1.n - 1].get())
                          ->AddColumn(e, step.cop, step.alias, step.n1 ? true : false, step.si);
          break;
        }
        case CompiledQuery::StepType::CREATE_VC: {
          DEBUG_ASSERT(step.t1.n < 0 && ta[-step.t1.n - 1]->TableType() == TType::TEMP_TABLE);
          TempTable *t = (TempTable *)ta[-step.t1.n - 1].get();

          DEBUG_ASSERT(t);
          if (step.mysql_expr.size() > 0) {
            // vcolumn::VirtualColumn for Expression
            DEBUG_ASSERT(step.mysql_expr.size() == 1);
            MultiIndex *mind = (step.t2.n == step.t1.n) ? t->GetOutputMultiIndexP() : t->GetMultiIndexP();
            int c = ((TempTable *)ta[-step.t1.n - 1].get())
                        ->AddVirtColumn(CreateColumnFromExpression(step.mysql_expr, t, step.t1.n, mind), step.a1.n);
            ASSERT(c == step.a1.n, "AddVirtColumn failed");
          } else if (step.virt_cols.size() > 0) {
            // vcolumn::VirtualColumn for IN
            ColumnType ct;
            if (step.a2.n != common::NULL_VALUE_32)
              ct = ((TempTable *)ta[-step.t1.n - 1].get())->GetVirtualColumn(step.a2.n)->Type();
            std::vector<vcolumn::VirtualColumn *> vcs;
            for (uint i = 0; i < step.virt_cols.size(); i++)
              vcs.push_back(((TempTable *)ta[-step.t1.n - 1].get())->GetVirtualColumn(step.virt_cols[i]));
            int c = ((TempTable *)ta[-step.t1.n - 1].get())
                        ->AddVirtColumn(new vcolumn::InSetColumn(ct, t->GetMultiIndexP(), vcs), step.a1.n);
            ASSERT(c == step.a1.n, "AddVirtColumn failed");
          } else if (step.a2.n != common::NULL_VALUE_32) {
            // vcolumn::VirtualColumn for PhysicalColumn
            JustATable *t_src = ta[-step.t2.n - 1].get();
            PhysicalColumn *phc;
            MultiIndex *mind = (step.t2.n == step.t1.n) ? t->GetOutputMultiIndexP() : t->GetMultiIndexP();
            int dim = (step.t2.n == step.t1.n) ? 0 : t->GetDimension(step.t2);
            phc = (PhysicalColumn *)t_src->GetColumn(step.a2.n >= 0 ? step.a2.n : -step.a2.n - 1);
            int c = ((TempTable *)ta[-step.t1.n - 1].get())
                        ->AddVirtColumn(
                            new vcolumn::SingleColumn(phc, mind, step.t2.n, step.a2.n, ta[-step.t2.n - 1].get(), dim),
                            step.a1.n);
            ASSERT(c == step.a1.n, "AddVirtColumn failed");
          } else {
            // vcolumn::VirtualColumn for Subquery
            DEBUG_ASSERT(ta[-step.t2.n - 1]->TableType() == TType::TEMP_TABLE);
            int c =
                ((TempTable *)ta[-step.t1.n - 1].get())
                    ->AddVirtColumn(new vcolumn::SubSelectColumn(
                                        dynamic_cast<TempTable *>(ta[-step.t2.n - 1].get()),
                                        step.n1 == 1 ? t->GetOutputMultiIndexP() : t->GetMultiIndexP(), t, step.t1.n),
                                    step.a1.n);
            ASSERT(c == step.a1.n, "AddVirtColumn failed");
          }
          break;
        }
        case CompiledQuery::StepType::ADD_ORDER: {
          DEBUG_ASSERT(step.t1.n < 0 && ta[-step.t1.n - 1]->TableType() == TType::TEMP_TABLE && step.n1 >= 0 &&
                       step.n1 < 2);
          DEBUG_ASSERT(step.a1.n >= 0 && step.a1.n < qu.NumOfVirtualColumns(step.t1));
          TempTable *loc_t = (TempTable *)ta[-step.t1.n - 1].get();
          loc_t->AddOrder(loc_t->GetVirtualColumn(step.a1.n),
                          (int)step.n1);  // step.n1 = 0 for asc, 1 for desc
          break;
        }
        case CompiledQuery::StepType::UNION:
          DEBUG_ASSERT(step.t1.n < 0 && step.t2.n < 0 && step.t3.n < 0);
          DEBUG_ASSERT(ta[-step.t2.n - 1]->TableType() == TType::TEMP_TABLE &&
                       (step.t3.n == common::NULL_VALUE_32 || ta[-step.t3.n - 1]->TableType() == TType::TEMP_TABLE));
          if (step.t1.n != step.t2.n)
            ta[-step.t1.n - 1] = TempTable::Create(*(TempTable *)ta[-step.t2.n - 1].get(), false);
          if (IsRoughQuery()) {
            if (step.t3.n == common::NULL_VALUE_32)
              ((TempTable *)ta[-step.t1.n - 1].get())
                  ->RoughUnion(nullptr, qu.IsResultTable(step.t1) ? sender : nullptr);
            else
              ((TempTable *)ta[-step.t1.n - 1].get())
                  ->RoughUnion((TempTable *)ta[-step.t3.n - 1].get(), qu.IsResultTable(step.t1) ? sender : nullptr);
          } else if (qu.IsResultTable(step.t1) && !qu.IsOrderedBy(step.t1) && step.n1)
            ((TempTable *)ta[-step.t1.n - 1].get())
                ->Union((TempTable *)ta[-step.t3.n - 1].get(), (int)step.n1, sender, global_limits.first,
                        global_limits.second);
          else {
            if (step.t3.n == common::NULL_VALUE_32)
              ((TempTable *)ta[-step.t1.n - 1].get())->Union(nullptr, (int)step.n1);
            else {
              ((TempTable *)ta[-step.t1.n - 1].get())->Union((TempTable *)ta[-step.t3.n - 1].get(), (int)step.n1);
              ta[-step.t3.n - 1].reset();
            }
          }
          break;
        case CompiledQuery::StepType::RESULT:
          DEBUG_ASSERT(step.t1.n < 0 && static_cast<size_t>(-step.t1.n - 1) < ta.size() &&
                       ta[-step.t1.n - 1]->TableType() == TType::TEMP_TABLE);
          output_table = (TempTable *)ta[-step.t1.n - 1].get();
          break;
        case CompiledQuery::StepType::STEP_ERROR:
          tianmu_control_.lock(m_conn->GetThreadID()) << "ERROR in step " << step.alias << system::unlock;
          break;
        default:
          tianmu_control_.lock(m_conn->GetThreadID())
              << "ERROR: unsupported type of CQStep (" << static_cast<int>(step.type) << ")" << system::unlock;
      }
    } catch (...) {
      for (auto &c : conds) delete c;
      throw;
    }
  }

  for (auto &c : conds) delete c;

  // NOTE: output_table is sent out of this function and should be managed
  // elsewhere. before deleting all TempTables but output_table those have to be
  // detected there are used by output_table

  return output_table;
}
adofsauron commented 1 year ago

The element node of mysql needs to be converted to the predicate description of stonedb

classItem__inherit__graph