From 53ea7673a70fd3eeb425b8da8d56ce8104500b3a Mon Sep 17 00:00:00 2001 From: tolyrria <2292493757@qq.com> Date: Sun, 1 Dec 2024 17:43:26 +0800 Subject: [PATCH 1/4] wsr_connector --- mysql-test/mysql-source-code-meta.patch | 406 +++-- mysql-test/suite/ctc/r/ctc_bit_analyze.result | 2 +- .../suite/ctc/r/ctc_cond_pushdown.result | 1384 ++++++++++++++++- .../ctc/r/ctc_cond_pushdown_explain.result | 986 +++++++++++- mysql-test/suite/ctc/r/ctc_datatype.result | 266 ++++ .../suite/ctc/r/ctc_datetime_analyze.result | 2 +- mysql-test/suite/ctc/r/ctc_ddl.result | 12 - mysql-test/suite/ctc/r/ctc_dml_ignore.result | 190 +++ mysql-test/suite/ctc/r/ctc_update_time.result | 8 +- mysql-test/suite/ctc/t/ctc_cond_pushdown.test | 358 ++++- .../ctc/t/ctc_cond_pushdown_explain.test | 280 +++- mysql-test/suite/ctc/t/ctc_datatype.test | 97 ++ mysql-test/suite/ctc/t/ctc_ddl.test | 12 - mysql-test/suite/ctc/t/ctc_dml_ignore.test | 91 ++ storage/ctc/CMakeLists.txt | 19 +- storage/ctc/ctc_cbo.cc | 22 +- storage/ctc/ctc_cbo.h | 5 +- storage/ctc/ctc_ddl_rewriter_plugin.cc | 29 +- storage/ctc/ctc_meta_data.cc | 18 +- storage/ctc/ctc_meta_data.h | 3 + storage/ctc/ctc_mysql_proxy.cc | 46 +- storage/ctc/ctc_srv.h | 121 +- storage/ctc/ctc_srv_mq_stub.cc | 239 ++- storage/ctc/ctc_stats.cc | 3 +- storage/ctc/ctc_util.cc | 1128 ++++++++++---- storage/ctc/ctc_util.h | 91 +- storage/ctc/datatype_cnvrt_4_index_search.cc | 34 +- storage/ctc/datatype_cnvrtr.cc | 110 +- storage/ctc/datatype_cnvrtr.h | 4 +- storage/ctc/ha_ctc.cc | 618 +++----- storage/ctc/ha_ctc.h | 139 +- storage/ctc/ha_ctc_ddl.h | 4 +- storage/ctc/ha_ctc_pq.cc | 515 ++++++ storage/ctc/ha_ctc_pq.h | 168 ++ storage/ctc/ha_ctcpart.cc | 68 +- storage/ctc/ha_ctcpart.h | 10 +- storage/ctc/srv_mq_msg.h | 59 + 37 files changed, 6554 insertions(+), 993 deletions(-) create mode 100644 storage/ctc/ha_ctc_pq.cc create mode 100644 storage/ctc/ha_ctc_pq.h diff --git a/mysql-test/mysql-source-code-meta.patch b/mysql-test/mysql-source-code-meta.patch index 2b5f319..131aad1 100644 --- a/mysql-test/mysql-source-code-meta.patch +++ b/mysql-test/mysql-source-code-meta.patch @@ -279,7 +279,7 @@ index d08718a1..e7d00b24 100644 if (ddse->dict_set_server_version == nullptr || ddse->dict_set_server_version()) { diff --git a/sql/dd/impl/cache/dictionary_client.cc b/sql/dd/impl/cache/dictionary_client.cc -index 80638063..c649fa53 100644 +index 80638063..8ef10d3a 100644 --- a/sql/dd/impl/cache/dictionary_client.cc +++ b/sql/dd/impl/cache/dictionary_client.cc @@ -93,6 +93,7 @@ @@ -771,7 +771,7 @@ index 065400f1..da58b045 100644 for (System_tables::Const_iterator it = diff --git a/sql/dd/impl/upgrade/server.cc b/sql/dd/impl/upgrade/server.cc -index 1e3ce91c..48125691 100644 +index 1e3ce91c..009423b8 100644 --- a/sql/dd/impl/upgrade/server.cc +++ b/sql/dd/impl/upgrade/server.cc @@ -518,12 +518,12 @@ static void create_upgrade_file() { @@ -866,7 +866,7 @@ index ebda371e..6310acc5 100644 // Read stage of upgrade from the file. Upgrade_status upgrade_status; diff --git a/sql/handler.cc b/sql/handler.cc -index 217a0c19..fe900ebd 100644 +index 217a0c19..5e93df0f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -769,11 +769,13 @@ int ha_initialize_handlerton(st_plugin_int *plugin) { @@ -1107,6 +1107,18 @@ index 0530ca15..bab9b083 100644 enum_binlog_command binlog_command, const char *query, size_t query_length, const char *db, const char *table_name); +diff --git a/sql/locking_service.cc b/sql/locking_service.cc +index 9ca8e21a..ef215f3d 100644 +--- a/sql/locking_service.cc ++++ b/sql/locking_service.cc +@@ -56,7 +56,6 @@ class Locking_service_deadlock_error_handler : public Internal_error_handler { + my_error(ER_LOCKING_SERVICE_DEADLOCK, MYF(0)); + return true; + } else if (sql_errno == ER_LOCK_WAIT_TIMEOUT) { +- my_error(ER_LOCKING_SERVICE_TIMEOUT, MYF(0)); + return true; + } + diff --git a/sql/log.cc b/sql/log.cc index 4da945ac..fc6f9c5b 100644 --- a/sql/log.cc @@ -1158,10 +1170,33 @@ index 4da945ac..fc6f9c5b 100644 goto err; } diff --git a/sql/mdl.cc b/sql/mdl.cc -index da9ff9ed..410b686d 100644 +index da9ff9ed..cd77e0a7 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc -@@ -1654,6 +1654,25 @@ bool MDL_lock::needs_hton_notification( +@@ -22,11 +22,6 @@ + + #include "sql/mdl.h" + +-#include +-#include +-#include +-#include +- + #include "lf.h" + #include "m_ctype.h" + #include "my_dbug.h" +@@ -53,6 +48,10 @@ + #include "sql/debug_sync.h" + #include "sql/thr_malloc.h" + ++ ++#define DEFAULT_DDL_WAIT_LOCK_TIMT 31536000 ++#define DEFAULT_WAIT_LOCK_TIMT 3600 ++ + extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info; + + static PSI_memory_key key_memory_MDL_context_acquire_locks; +@@ -1654,6 +1653,25 @@ bool MDL_lock::needs_hton_notification( } } @@ -1187,7 +1222,7 @@ index da9ff9ed..410b686d 100644 /** Auxiliary functions needed for creation/destruction of MDL_ticket objects. -@@ -2901,8 +2920,11 @@ bool MDL_context::try_acquire_lock_impl(MDL_request *mdl_request, +@@ -2901,8 +2919,11 @@ bool MDL_context::try_acquire_lock_impl(MDL_request *mdl_request, We need to notify/get permission from storage engines before acquiring X lock if it is requested in one of namespaces interesting for SEs. */ @@ -1201,7 +1236,7 @@ index da9ff9ed..410b686d 100644 mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PRE_ACQUIRE_NOTIFY); bool victimized; -@@ -2916,6 +2938,7 @@ bool MDL_context::try_acquire_lock_impl(MDL_request *mdl_request, +@@ -2916,6 +2937,7 @@ bool MDL_context::try_acquire_lock_impl(MDL_request *mdl_request, mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PENDING); } @@ -1209,61 +1244,7 @@ index da9ff9ed..410b686d 100644 retry: /* -@@ -3034,6 +3057,26 @@ retry: - m_ticket_store.push_front(mdl_request->duration, ticket); - mdl_request->ticket = ticket; - -+ if ((mdl_request->type == MDL_EXCLUSIVE && -+ MDL_lock::needs_hton_notification(key->mdl_namespace())) || -+ is_notify_ctc_se(mdl_request->type, key->mdl_namespace())) { -+ -+ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PRE_ACQUIRE_NOTIFY); -+ -+ bool victimized; -+ if (m_owner->notify_hton_pre_acquire_exclusive(key, &victimized)) { -+ -+ ticket->m_hton_notified = false; -+ release_lock(mdl_request->duration, ticket); -+ mdl_request->ticket = nullptr; -+ my_error(victimized ? ER_LOCK_DEADLOCK : ER_LOCK_REFUSED_BY_ENGINE, -+ MYF(0)); -+ return true; -+ } -+ -+ ticket->m_hton_notified = true; -+ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PENDING); -+ } - mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED); - return false; - } -@@ -3147,6 +3190,26 @@ slow_path: - m_ticket_store.push_front(mdl_request->duration, ticket); - mdl_request->ticket = ticket; - -+ if ((mdl_request->type == MDL_EXCLUSIVE && -+ MDL_lock::needs_hton_notification(key->mdl_namespace())) || -+ is_notify_ctc_se(mdl_request->type, key->mdl_namespace())) { -+ -+ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PRE_ACQUIRE_NOTIFY); -+ -+ bool victimized; -+ if (m_owner->notify_hton_pre_acquire_exclusive(key, &victimized)) { -+ -+ ticket->m_hton_notified = false; -+ release_lock(mdl_request->duration, ticket); -+ mdl_request->ticket = nullptr; -+ my_error(victimized ? ER_LOCK_DEADLOCK : ER_LOCK_REFUSED_BY_ENGINE, -+ MYF(0)); -+ return true; -+ } -+ ticket->m_hton_notified = true; -+ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PENDING); -+ } -+ - mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED); - } else - *out_ticket = ticket; -@@ -3207,10 +3270,11 @@ bool MDL_context::clone_ticket(MDL_request *mdl_request) { +@@ -3207,10 +3229,11 @@ bool MDL_context::clone_ticket(MDL_request *mdl_request) { of storage engines we need to notify/get permission from SEs similarly to situation when lock acquired. */ @@ -1278,7 +1259,7 @@ index da9ff9ed..410b686d 100644 mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PRE_ACQUIRE_NOTIFY); bool victimized; -@@ -3224,6 +3288,7 @@ bool MDL_context::clone_ticket(MDL_request *mdl_request) { +@@ -3224,6 +3247,7 @@ bool MDL_context::clone_ticket(MDL_request *mdl_request) { ticket->m_hton_notified = true; mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PENDING); @@ -1286,64 +1267,216 @@ index da9ff9ed..410b686d 100644 } ticket->m_lock = mdl_request->ticket->m_lock; -@@ -3275,6 +3340,28 @@ bool MDL_context::clone_ticket(MDL_request *mdl_request) { +@@ -3275,6 +3299,7 @@ bool MDL_context::clone_ticket(MDL_request *mdl_request) { mdl_request->ticket = ticket; m_ticket_store.push_front(mdl_request->duration, ticket); + -+ if ((mdl_request->type == MDL_EXCLUSIVE && -+ MDL_lock::needs_hton_notification(mdl_request->key.mdl_namespace())) || -+ is_notify_ctc_se(mdl_request->type, mdl_request->key.mdl_namespace())) { + mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED); + + return false; +@@ -3342,43 +3367,67 @@ void MDL_lock::object_lock_notify_conflicting_locks(MDL_context *ctx, + } + } + +-/** +- Acquire one lock with waiting for conflicting locks to go away if needed. + +- @param [in,out] mdl_request Lock request object for lock to be acquired ++bool MDL_context::acquire_lock_without_wait(MDL_request *mdl_request) { + +- @param lock_wait_timeout Seconds to wait before timeout. ++ MDL_ticket *ticket = nullptr; + -+ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PRE_ACQUIRE_NOTIFY); ++ if (try_acquire_lock(mdl_request)) return true; ++ ++ if (!mdl_request->ticket) { ++ /* We have failed to acquire lock instantly. */ ++ DEBUG_SYNC(get_thd(), "mdl_acquire_lock_wait"); ++ my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0)); ++ return true; ++ } ++ ++ ticket = mdl_request->ticket; ++ if (acquire_lock_remote(mdl_request, ticket)) return true; + ++ if (mdl_request->ticket) return false; ++ ++ return true; ++} + ++/* + @retval false Success. MDL_request::ticket points to the ticket + for the lock. + @retval true Failure (Out of resources or waiting is aborted), + */ ++bool MDL_context::acquire_lock_remote(MDL_request *mdl_request, MDL_ticket *ticket) { ++ if ((mdl_request->type == MDL_EXCLUSIVE && ++ MDL_lock::needs_hton_notification(mdl_request->key.mdl_namespace())) || ++ is_notify_ctc_se(mdl_request->type, mdl_request->key.mdl_namespace())) { + +-bool MDL_context::acquire_lock(MDL_request *mdl_request, +- Timeout_type lock_wait_timeout) { +- if (lock_wait_timeout == 0) { +- /* +- Resort to try_acquire_lock() in case of zero timeout. +- +- This allows to avoid unnecessary deadlock detection attempt and "fake" +- deadlocks which might result from it. +- In case of failure to acquire lock, try_acquire_lock() preserves +- invariants by updating MDL_lock::fast_path_state and obtrusive locks +- count. It also performs SE notification if needed. +- */ +- if (try_acquire_lock(mdl_request)) return true; +- +- if (!mdl_request->ticket) { +- /* We have failed to acquire lock instantly. */ +- DEBUG_SYNC(get_thd(), "mdl_acquire_lock_wait"); +- my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0)); +- return true; ++ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PRE_ACQUIRE_NOTIFY); + bool victimized; -+ if (m_owner->notify_hton_pre_acquire_exclusive(&mdl_request->key, -+ &victimized)) { -+ ticket->m_hton_notified = false; -+ release_lock(mdl_request->duration, ticket); -+ mdl_request->ticket = nullptr; -+ my_error(victimized ? ER_LOCK_DEADLOCK : ER_LOCK_REFUSED_BY_ENGINE, -+ MYF(0)); -+ return true; -+ } ++ if (m_owner->notify_hton_pre_acquire_exclusive(&mdl_request->key, &victimized)) { ++ ticket->m_hton_notified = false; ++ release_lock(mdl_request->duration, ticket); ++ mdl_request->ticket = nullptr; ++ return true; + } +- return false; + ticket->m_hton_notified = true; -+ + mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PENDING); -+ } + } ++ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED); ++ return false; ++} + - mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED); ++/** ++ Acquire one lock with waiting for conflicting locks to go away if needed. ++ ++ @param [in,out] mdl_request Lock request object for lock to be acquired +- /* Normal, non-zero timeout case. */ ++ @param lock_wait_timeout Seconds to wait before timeout. ++ ++ @retval false Success. MDL_request::ticket points to the ticket ++ for the lock. ++ @retval true Failure (Out of resources or waiting is aborted), ++*/ + ++bool MDL_context::acquire_lock_local(MDL_request *mdl_request, ++ Timeout_type lock_wait_timeout) { + MDL_lock *lock; + MDL_ticket *ticket = nullptr; + struct timespec abs_timeout; +@@ -3484,8 +3533,9 @@ bool MDL_context::acquire_lock(MDL_request *mdl_request, + /* abs_timeout is far away. Wait a short while and notify locks. */ + wait_status = m_wait.timed_wait(m_owner, &abs_shortwait, false, + mdl_request->key.get_wait_state_name()); +- +- if (wait_status != MDL_wait::WS_EMPTY) break; ++ if (wait_status != MDL_wait::WS_EMPTY) { ++ break; ++ } + + if (lock->needs_connection_check() && !m_owner->is_connected()) { + /* +@@ -3553,10 +3603,11 @@ bool MDL_context::acquire_lock(MDL_request *mdl_request, + my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0)); + break; + case MDL_wait::KILLED: +- if (get_owner()->is_killed() == ER_QUERY_TIMEOUT) ++ if (get_owner()->is_killed() == ER_QUERY_TIMEOUT) { + my_error(ER_QUERY_TIMEOUT, MYF(0)); +- else ++ } else { + my_error(ER_QUERY_INTERRUPTED, MYF(0)); ++ } + break; + default: + assert(0); +@@ -3581,6 +3632,81 @@ bool MDL_context::acquire_lock(MDL_request *mdl_request, return false; -@@ -3576,6 +3663,27 @@ bool MDL_context::acquire_lock(MDL_request *mdl_request, - m_ticket_store.push_front(mdl_request->duration, ticket); - mdl_request->ticket = ticket; + } -+ if ((mdl_request->type == MDL_EXCLUSIVE && -+ MDL_lock::needs_hton_notification(mdl_request->key.mdl_namespace())) || -+ is_notify_ctc_se(mdl_request->type, mdl_request->key.mdl_namespace())) { ++/** ++ Acquire lock from both nodes + -+ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PRE_ACQUIRE_NOTIFY); ++ @param [in,out] mdl_request Lock request object for lock to be acquired + -+ bool victimized; -+ if (m_owner->notify_hton_pre_acquire_exclusive(&mdl_request->key, -+ &victimized)) { -+ ticket->m_hton_notified = false; -+ release_lock(mdl_request->duration, ticket); -+ mdl_request->ticket = nullptr; -+ my_error(victimized ? ER_LOCK_DEADLOCK : ER_LOCK_REFUSED_BY_ENGINE, -+ MYF(0)); ++ @param lock_wait_timeout Seconds to wait before timeout. ++ ++ @retval false Success. MDL_request::ticket points to the ticket ++ for the lock. ++ @retval true Failure (Out of resources or waiting is aborted), ++*/ ++ ++bool MDL_context::acquire_lock(MDL_request *mdl_request, Timeout_type lock_wait_timeout) { ++ ++ /* ++ Resort to try_acquire_lock() in case of zero timeout. ++ ++ This allows to avoid unnecessary deadlock detection attempt and "fake" ++ deadlocks which might result from it. ++ In case of failure to acquire lock, try_acquire_lock() preserves ++ invariants by updating MDL_lock::fast_path_state and obtrusive locks ++ count. It also performs SE notification if needed. ++ */ ++ if (lock_wait_timeout == 0) { ++ if (acquire_lock_without_wait(mdl_request)) { + return true; + } -+ ticket->m_hton_notified = true; ++ return false; ++ } + -+ mysql_mdl_set_status(ticket->m_psi, MDL_ticket::PENDING); ++ /*non-zero timeout case*/ ++ THD* thd = get_thd(); ++ uint64 seed = (uint64)thd; ++ if (mdl_request->type == MDL_EXCLUSIVE && MDL_lock::needs_hton_notification(mdl_request->key.mdl_namespace())) { ++ if (lock_wait_timeout == DEFAULT_DDL_WAIT_LOCK_TIMT || lock_wait_timeout == DEFAULT_WAIT_LOCK_TIMT) { ++ lock_wait_timeout = static_cast(seed % 10 + 1); ++ } + } + - mysql_mdl_set_status(ticket->m_psi, MDL_ticket::GRANTED); - - return false; -@@ -4234,6 +4342,29 @@ void MDL_context::release_locks_stored_before(enum_mdl_duration duration, ++ struct timespec abs_start_time; ++ struct timespec abs_end_time; ++ set_timespec(&abs_start_time, 0); ++ set_timespec(&abs_end_time, lock_wait_timeout); ++ Timeout_type remaining_wait_time = lock_wait_timeout; ++ MDL_ticket *ticket = nullptr; ++ ++ while (cmp_timespec(&abs_start_time, &abs_end_time) <= 0) { ++ set_timespec(&abs_start_time, 0); ++ remaining_wait_time = static_cast(diff_timespec(&abs_end_time, &abs_start_time) / 1000000000ULL); ++ if (lock_wait_timeout == 1) { ++ remaining_wait_time += 1; ++ } ++ if (remaining_wait_time <= 0) break; ++ if (acquire_lock_local(mdl_request, remaining_wait_time)) { ++ return true; ++ } ++ ticket = mdl_request->ticket; ++ if (acquire_lock_remote(mdl_request, ticket)) { ++ unsigned int sleep_duration = get_random() % 1000000; ++ my_sleep(sleep_duration); ++ continue; ++ } else { ++ if (mdl_request->ticket) { ++ return false; ++ } else { ++ break; ++ } ++ } ++ } ++ ++ if(mdl_request->ticket) return false; ++ my_error(ER_LOCK_REFUSED_BY_ENGINE, MYF(0)); ++ return true; ++} ++ + class MDL_request_cmp { + public: + bool operator()(const MDL_request *req1, const MDL_request *req2) { +@@ -4234,6 +4360,29 @@ void MDL_context::release_locks_stored_before(enum_mdl_duration duration, } } @@ -1374,10 +1507,20 @@ index da9ff9ed..410b686d 100644 Release all explicit locks in the context which correspond to the same name/object as this lock request. diff --git a/sql/mdl.h b/sql/mdl.h -index f1f49f06..0127906c 100644 +index f1f49f06..b810f0ac 100644 --- a/sql/mdl.h +++ b/sql/mdl.h -@@ -1444,6 +1444,14 @@ class MDL_context { +@@ -1416,6 +1416,9 @@ class MDL_context { + MDL_context(); + void destroy(); + ++ bool acquire_lock_without_wait(MDL_request *mdl_request); ++ bool acquire_lock_remote(MDL_request *mdl_request, MDL_ticket *ticket); ++ bool acquire_lock_local(MDL_request *mdl_request, Timeout_type lock_wait_timeout); + bool try_acquire_lock(MDL_request *mdl_request); + bool acquire_lock(MDL_request *mdl_request, Timeout_type lock_wait_timeout); + bool acquire_locks(MDL_request_list *requests, +@@ -1444,6 +1447,14 @@ class MDL_context { void release_all_locks_for_name(MDL_ticket *ticket); void release_locks(MDL_release_locks_visitor *visitor); void release_lock(MDL_ticket *ticket); @@ -1392,8 +1535,15 @@ index f1f49f06..0127906c 100644 bool owns_equal_or_stronger_lock(const MDL_key *mdl_key, enum_mdl_type mdl_type); +@@ -1772,4 +1783,4 @@ class MDL_lock_is_owned_visitor : public MDL_context_visitor { + bool m_exists; + }; + +-#endif ++#endif +\ No newline at end of file diff --git a/sql/mysqld.cc b/sql/mysqld.cc -index 50b76e2f..080fdf93 100644 +index 50b76e2f..2410960a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1216,6 +1216,7 @@ handlerton *heap_hton; @@ -1431,7 +1581,7 @@ index 50b76e2f..080fdf93 100644 /* Set opt_super_readonly here because if opt_super_readonly is set diff --git a/sql/mysqld.h b/sql/mysqld.h -index 0d7d41c4..b3f86eb6 100644 +index 0d7d41c4..52ce7864 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -358,6 +358,7 @@ extern handlerton *myisam_hton; @@ -1443,7 +1593,7 @@ index 0d7d41c4..b3f86eb6 100644 extern ulong opt_server_id_mask; extern const char *load_default_groups[]; diff --git a/sql/mysqld_thd_manager.cc b/sql/mysqld_thd_manager.cc -index 902fe2b2..2fad578e 100644 +index 902fe2b2..d1c5fbdd 100644 --- a/sql/mysqld_thd_manager.cc +++ b/sql/mysqld_thd_manager.cc @@ -48,6 +48,7 @@ @@ -1520,10 +1670,18 @@ index e16b39c4..efdfba2c 100644 /* Compressing the gtid_executed table. */ if (gtid_state->compress(thd)) { diff --git a/sql/sql_class.cc b/sql/sql_class.cc -index c171f0bb..a34904db 100644 +index c171f0bb..6fc75f7c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc -@@ -2890,6 +2890,17 @@ void THD::update_slow_query_status() { +@@ -408,6 +408,7 @@ THD::THD(bool enable_plugins) + status_var_aggregated(false), + m_connection_attributes(), + m_current_query_cost(0), ++ pre_sess_addr(0), + m_current_query_partial_plans(0), + m_main_security_ctx(this), + m_security_ctx(&m_main_security_ctx), +@@ -2890,6 +2891,17 @@ void THD::update_slow_query_status() { server_status |= SERVER_QUERY_WAS_SLOW; } @@ -1542,7 +1700,7 @@ index c171f0bb..a34904db 100644 Initialize the transactional ddl context when executing CREATE TABLE ... SELECT command with engine which supports atomic DDL. diff --git a/sql/sql_class.h b/sql/sql_class.h -index 9f68530b..c7004b47 100644 +index 9f68530b..8a767cd7 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -841,6 +841,7 @@ class THD : public MDL_context_owner, @@ -1553,7 +1711,15 @@ index 9f68530b..c7004b47 100644 MDL_context mdl_context; /** -@@ -4417,6 +4418,29 @@ class THD : public MDL_context_owner, +@@ -1019,6 +1020,7 @@ class THD : public MDL_context_owner, + @sa system_status_var::last_query_cost + */ + double m_current_query_cost; ++ uint64_t pre_sess_addr; + /** + Current query partial plans. + @sa system_status_var::last_query_partial_plans +@@ -4417,6 +4419,29 @@ class THD : public MDL_context_owner, @param thd parent session */ void copy_table_access_properties(THD *thd); @@ -1740,7 +1906,7 @@ index 662f5222..68e3ddd2 100644 Now we can try removing database directory. diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc -index 70d9c1ff..b98e6ecb 100644 +index 70d9c1ff..c4a54c69 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2681,8 +2681,8 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, @@ -1874,7 +2040,7 @@ index 3860d342..e89ca4c0 100644 if (test_plugin_options(&tmp_root, &tmp, argc, argv)) tmp.state = PLUGIN_IS_DISABLED; diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc -index 7bd705b4..17c49cea 100644 +index 7bd705b4..b5e68b9d 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -35,6 +35,7 @@ @@ -1906,7 +2072,7 @@ index 7bd705b4..17c49cea 100644 } } -+ hton->pre_sess_addr = *(uint64_t *)thd_get_ha_data(thd, hton); ++ thd->pre_sess_addr = *(uint64_t *)thd_get_ha_data(thd, hton); if (collect_and_lock_fk_tables_for_rename_table( thd, ren_table->db, old_alias, from_table, new_db, new_alias, hton, fk_invalidator)) { @@ -1914,7 +2080,7 @@ index 7bd705b4..17c49cea 100644 happen. So it is safe to clear invalidator. */ fk_invalidator->clear(); -+ hton->pre_sess_addr = 0; ++ thd->pre_sess_addr = 0; return true; } } @@ -1923,7 +2089,7 @@ index 7bd705b4..17c49cea 100644 - from_table, new_db, new_alias)) + from_table, new_db, new_alias)) { + -+ hton->pre_sess_addr = 0; ++ thd->pre_sess_addr = 0; return true; + } @@ -1933,15 +2099,15 @@ index 7bd705b4..17c49cea 100644 */ fk_invalidator->clear(); } -+ hton->pre_sess_addr = 0; ++ thd->pre_sess_addr = 0; return true; } -+ hton->pre_sess_addr = 0; ++ thd->pre_sess_addr = 0; /* If RENAME TABLE is non-atomic but we have not committed the above diff --git a/sql/sql_select.cc b/sql/sql_select.cc -index 5963cf6e..3218795f 100644 +index 5963cf6e..0479852f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2755,7 +2755,7 @@ void QEP_TAB::push_index_cond(const JOIN_TAB *join_tab, uint keyno, @@ -2114,7 +2280,7 @@ index 04bc666a..76602d92 100644 thd->locked_tables_list.rename_locked_table( table_list, alter_ctx.new_db, alter_ctx.new_name, diff --git a/sql/sql_tmp_table.cc b/sql/sql_tmp_table.cc -index 2063261b..1c71f772 100644 +index 2063261b..faa2d3d6 100644 --- a/sql/sql_tmp_table.cc +++ b/sql/sql_tmp_table.cc @@ -558,12 +558,15 @@ class Cache_temp_engine_properties { @@ -2304,7 +2470,7 @@ index 9f955ad4..178d46e1 100644 (thd->variables.option_bits & OPTION_TABLE_LOCK)) { /* Safety if one did "drop table" on locked tables */ diff --git a/sql/window_iterators.cc b/sql/window_iterators.cc -index cb0f1409..a6da7249 100644 +index cb0f1409..64c02879 100644 --- a/sql/window_iterators.cc +++ b/sql/window_iterators.cc @@ -159,7 +159,7 @@ bool buffer_record_somewhere(THD *thd, Window *w, int64 rowno) { diff --git a/mysql-test/suite/ctc/r/ctc_bit_analyze.result b/mysql-test/suite/ctc/r/ctc_bit_analyze.result index fccc1c3..7d18c30 100644 --- a/mysql-test/suite/ctc/r/ctc_bit_analyze.result +++ b/mysql-test/suite/ctc/r/ctc_bit_analyze.result @@ -44,7 +44,7 @@ Warnings: Note 1003 /* select#1 */ select `test`.`tbl_bit`.`num` AS `num` from `test`.`tbl_bit` where ((`test`.`tbl_bit`.`num` > 0x02) and (`test`.`tbl_bit`.`num` < 0x0d)) explain select * from tbl_bit where num >= b'0010' and num <= b'1101'; id select_type table partitions type possible_keys key key_len ref rows filtered Extra -1 SIMPLE tbl_bit NULL range idx_num idx_num 2 NULL 12 100.00 Using where; Using index +1 SIMPLE tbl_bit NULL index idx_num idx_num 2 NULL 16 75.00 Using where; Using index Warnings: Note 1003 /* select#1 */ select `test`.`tbl_bit`.`num` AS `num` from `test`.`tbl_bit` where ((`test`.`tbl_bit`.`num` >= 0x02) and (`test`.`tbl_bit`.`num` <= 0x0d)) drop table tbl_bit; diff --git a/mysql-test/suite/ctc/r/ctc_cond_pushdown.result b/mysql-test/suite/ctc/r/ctc_cond_pushdown.result index 22397f7..ccc5617 100644 --- a/mysql-test/suite/ctc/r/ctc_cond_pushdown.result +++ b/mysql-test/suite/ctc/r/ctc_cond_pushdown.result @@ -185,9 +185,41 @@ c1 c2 c3 c4 c5 c6 select * from t1 where c2 = 3; c1 c2 c3 c4 c5 c6 3 3 3 3 3 3 +select * from t1 where 255 = c3; +c1 c2 c3 c4 c5 c6 +select * from t1 where 255 <=> c3; +c1 c2 c3 c4 c5 c6 +select * from t1 where 3 = c1; +c1 c2 c3 c4 c5 c6 +3 3 3 3 3 3 +select * from t1 where 3 < c1; +c1 c2 c3 c4 c5 c6 +4 4 4 4 4 4 +8 8 127 255 8 8 +select * from t1 where 3 != c1; +c1 c2 c3 c4 c5 c6 +1 1 1 1 1 1 +2 2 2 2 2 2 +4 4 4 4 4 4 +8 8 127 255 8 8 +select * from t1 where 3 = c2; +c1 c2 c3 c4 c5 c6 +3 3 3 3 3 3 +select * from t1 where 3 <=> c2; +c1 c2 c3 c4 c5 c6 +3 3 3 3 3 3 select * from t1 where c4 = 255; c1 c2 c3 c4 c5 c6 8 8 127 255 8 8 +select * from t1 where 255 = c4; +c1 c2 c3 c4 c5 c6 +8 8 127 255 8 8 +select * from t1 where c4 <=> 255; +c1 c2 c3 c4 c5 c6 +8 8 127 255 8 8 +select * from t1 where 255 <=> c4; +c1 c2 c3 c4 c5 c6 +8 8 127 255 8 8 select * from t2 where c3 = 11.111; c1 c2 c3 c4 c5 c6 1.1 11.110 11.111 1.1 11.110 11.111 @@ -197,6 +229,15 @@ c1 c2 c3 c4 c5 c6 select * from t2 where c6 = 11.111; c1 c2 c3 c4 c5 c6 1.1 11.110 11.111 1.1 11.110 11.111 +select * from t2 where 11.111 = c3; +c1 c2 c3 c4 c5 c6 +1.1 11.110 11.111 1.1 11.110 11.111 +select * from t2 where 1.1 = c4; +c1 c2 c3 c4 c5 c6 +1.1 11.110 11.111 1.1 11.110 11.111 +select * from t2 where 11.111 = c6; +c1 c2 c3 c4 c5 c6 +1.1 11.110 11.111 1.1 11.110 11.111 select * from t1 where null <=> null; c1 c2 c3 c4 c5 c6 1 1 1 1 1 1 @@ -236,8 +277,22 @@ c1 c2 c3 c4 c5 c6 3 3 3 3 3 3 4 4 4 4 4 4 8 8 127 255 8 8 -select * from t1 where c1 > 3 or c2 = 4 or c3 >=3 or c4 = 5 or (c1 > 1 and c2 < 5 and c3 > 2); +select * from t1 where null = c1; +c1 c2 c3 c4 c5 c6 +select * from t1 where null != c1; +c1 c2 c3 c4 c5 c6 +select * from t1 where null < c1; +c1 c2 c3 c4 c5 c6 +select * from t1 where null > c1; +c1 c2 c3 c4 c5 c6 +select * from t1 where null <=> c1; c1 c2 c3 c4 c5 c6 +NULL 5 NULL NULL NULL NULL +NULL 7 NULL NULL NULL NULL +select * from t1 where not null <=> c1; +c1 c2 c3 c4 c5 c6 +1 1 1 1 1 1 +2 2 2 2 2 2 3 3 3 3 3 3 4 4 4 4 4 4 8 8 127 255 8 8 @@ -496,6 +551,35 @@ c1 c2 c3 c4 c5 c6 3 3 3 3 3 3 4 4 4 4 4 4 8 8 127 255 8 8 +select * from t1 where 3 < c1 and 4 = c2 and 1 <= c3; +c1 c2 c3 c4 c5 c6 +4 4 4 4 4 4 +select * from t1 where 3 < c1 and 8 = c2; +c1 c2 c3 c4 c5 c6 +8 8 127 255 8 8 +select * from t1 where not c1 > 3; +c1 c2 c3 c4 c5 c6 +1 1 1 1 1 1 +2 2 2 2 2 2 +3 3 3 3 3 3 +select * from t1 where not (c1 > 3 and c2 = 4 and c3 >=1); +c1 c2 c3 c4 c5 c6 +1 1 1 1 1 1 +2 2 2 2 2 2 +NULL 5 NULL NULL NULL NULL +3 3 3 3 3 3 +NULL 7 NULL NULL NULL NULL +8 8 127 255 8 8 +select * from t1 where c1 = 1 xor c2 = 5; +c1 c2 c3 c4 c5 c6 +1 1 1 1 1 1 +select * from t1 where c1 = 1 xor c2 = 1; +c1 c2 c3 c4 c5 c6 +select * from t1 where 3 < c1 or 4 = c2 or 3 <= c3 or 5 = c4 or (1 < c1 and 5 > c2 and 2 < c3); +c1 c2 c3 c4 c5 c6 +3 3 3 3 3 3 +4 4 4 4 4 4 +8 8 127 255 8 8 select c1 from t10 where c2=69; c1 69 @@ -510,13 +594,33 @@ c1 2069 select c1,c2 from t11 where c2=4; c1 c2 +select c1 from t10 where 69=c2; +c1 +69 +select c1 from t10 where 69=c1; +c1 +69 +select c1 from t11 where 69=c2; +c1 +2069 +select c1 from t11 where 69=c1; +c1 +2069 +select c1,c2 from t11 where 4=c2; +c1 c2 select * from t13 where e_tinyint = 30; id a_integer b_char c_varchar d_deciaml e_tinyint f_bigint g_float h_date 3 33 b varchar 333 30 300 30.01 2022-09-23 +select * from t13 where 30 = e_tinyint; +id a_integer b_char c_varchar d_deciaml e_tinyint f_bigint g_float h_date +3 33 b varchar 333 30 300 30.01 2022-09-23 alter table t13 drop column d_deciaml; select * from t13 where e_tinyint = 30; id a_integer b_char c_varchar e_tinyint f_bigint g_float h_date 3 33 b varchar 30 300 30.01 2022-09-23 +select * from t13 where 30 = e_tinyint; +id a_integer b_char c_varchar e_tinyint f_bigint g_float h_date +3 33 b varchar 30 300 30.01 2022-09-23 select hex(c2) from t15 where c2 = 'abcde'; hex(c2) select hex(c2) from t15 where c2 = 0x61626364650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; @@ -525,6 +629,14 @@ hex(c2) select hex(c3) from t15 where c3 = 'abcde'; hex(c3) 6162636465 +select hex(c2) from t15 where 'abcde' = c2; +hex(c2) +select hex(c2) from t15 where 0x61626364650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 = c2; +hex(c2) +61626364650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +select hex(c3) from t15 where 'abcde' = c3; +hex(c3) +6162636465 select * from t5 where c1 = '01:01:01.01'; c1 c2 01:01:01 00:00:00 @@ -552,6 +664,31 @@ c1 c2 01:01:01 23:59:59 Warnings: Note 1292 Incorrect time value: '1999-12-31 23:59:59' for column 'c2' at row 1 +select * from t5 where '01:01:01.01' = c1; +c1 c2 +01:01:01 00:00:00 +01:01:01 23:59:59 +select * from t5 where '01:01:01.01' > c1; +c1 c2 +select * from t5 where '02:02:02' = c1; +c1 c2 +02:02:02 00:00:00 +02:02:02 13:13:13 +select * from t5 where '00:00:00' = c2; +c1 c2 +01:01:01 00:00:00 +02:02:02 00:00:00 +select * from t5 where '1000-01-01 00:00:00' = c2; +c1 c2 +01:01:01 00:00:00 +02:02:02 00:00:00 +Warnings: +Note 1292 Incorrect time value: '1000-01-01 00:00:00' for column 'c2' at row 1 +select * from t5 where '1999-12-31 23:59:59' = c2; +c1 c2 +01:01:01 23:59:59 +Warnings: +Note 1292 Incorrect time value: '1999-12-31 23:59:59' for column 'c2' at row 1 select * from t6 where c1 = '1000-01-01'; c1 c2 1000-01-01 1000-01-01 @@ -569,6 +706,24 @@ c1 c2 select * from t6 where c2 = '1000-01-01 00:00:00'; c1 c2 1000-01-01 1000-01-01 +select * from t6 where '1000-01-01' = c1; +c1 c2 +1000-01-01 1000-01-01 +select * from t6 where '1000-01-01' <=> c1; +c1 c2 +1000-01-01 1000-01-01 +select * from t6 where '1000-01-01 00:00:00' = c1; +c1 c2 +1000-01-01 1000-01-01 +select * from t6 where '1000-01-01 00:00:00' = c1; +c1 c2 +1000-01-01 1000-01-01 +select * from t6 where '1000-01-01' = c2; +c1 c2 +1000-01-01 1000-01-01 +select * from t6 where '1000-01-01 00:00:00' = c2; +c1 c2 +1000-01-01 1000-01-01 select * from t7 where c1 = '1000-01-01'; c1 c2 1000-01-01 00:00:00 1000-01-01 00:00:00 @@ -586,6 +741,24 @@ c1 c2 select * from t7 where c2 = '1000-01-01 00:00:00'; c1 c2 1000-01-01 00:00:00 1000-01-01 00:00:00 +select * from t7 where '1000-01-01' = c1; +c1 c2 +1000-01-01 00:00:00 1000-01-01 00:00:00 +select * from t7 where '1000-01-01' <=> c1; +c1 c2 +1000-01-01 00:00:00 1000-01-01 00:00:00 +select * from t7 where '1000-01-01 00:00:00' = c1; +c1 c2 +1000-01-01 00:00:00 1000-01-01 00:00:00 +select * from t7 where '1000-01-01 00:00:00' = c1; +c1 c2 +1000-01-01 00:00:00 1000-01-01 00:00:00 +select * from t7 where '1000-01-01' = c2; +c1 c2 +1000-01-01 00:00:00 1000-01-01 00:00:00 +select * from t7 where '1000-01-01 00:00:00' = c2; +c1 c2 +1000-01-01 00:00:00 1000-01-01 00:00:00 select * from t8 where c1 = '2000-01-01'; c1 c2 2000-01-01 00:00:00 2000-01-01 00:00:00 @@ -601,6 +774,27 @@ c1 c2 select * from t8 where c2 = '2000-01-01 00:00:00'; c1 c2 2000-01-01 00:00:00 2000-01-01 00:00:00 +select * from t8 where '2000-01-01' = c1; +c1 c2 +2000-01-01 00:00:00 2000-01-01 00:00:00 +select * from t8 where '2000-01-01' <=> c1; +c1 c2 +2000-01-01 00:00:00 2000-01-01 00:00:00 +select * from t8 where '2000-01-01 00:00:00' = c1; +c1 c2 +2000-01-01 00:00:00 2000-01-01 00:00:00 +select * from t8 where '2000-01-01 00:00:00' < c1; +c1 c2 +2008-02-29 00:00:00 2008-02-29 13:13:13 +select * from t8 where '2000-01-01 00:00:00' > c1; +c1 c2 +1999-12-31 00:00:00 1999-12-31 23:59:59 +select * from t8 where '2000-01-01' = c2; +c1 c2 +2000-01-01 00:00:00 2000-01-01 00:00:00 +select * from t8 where '2000-01-01 00:00:00' = c2; +c1 c2 +2000-01-01 00:00:00 2000-01-01 00:00:00 select * from t11 where c1 = 4; c1 c2 2004 NULL @@ -616,6 +810,24 @@ c1 c2 select * from t11 where '2004' = c1; c1 c2 2004 NULL +select * from t11 where 4 = c1; +c1 c2 +2004 NULL +select * from t11 where 4 <=> c1; +c1 c2 +2004 NULL +select * from t11 where 2004 = c1; +c1 c2 +2004 NULL +select * from t11 where '2004' = c1; +c1 c2 +2004 NULL +select * from t11 where 2004.0 = c1; +c1 c2 +2004 NULL +select * from t11 where c1 = '2004'; +c1 c2 +2004 NULL select * from t12 where IDA = 'aaa'; IDA aaa @@ -633,6 +845,9 @@ INSERT INTO tickets(title) VALUES('Refresh the computer of Ms. Lily'); SELECT * FROM tickets WHERE priority = 3; id title priority 1 Scan virus for computer A High +SELECT * FROM tickets WHERE 3 = priority; +id title priority +1 Scan virus for computer A High drop table if exists tickets; drop table if exists myset; Warnings: @@ -662,7 +877,1150 @@ a,d a,d a,d a,d +select * from myset where 'a' = col; +col +a +select * from myset where 'a,d' = col; +col +a,d +a,d +a,d +a,d +a,d +select * from myset where col like 'a,d'; +col +a,d +a,d +a,d +a,d +a,d drop table if exists myset; +drop table if exists t1; +CREATE TABLE t1(c1 tinyint, c2 tinyint not null, c3 tinyint signed, c4 tinyint unsigned, c5 int, c6 long, c7 bigint); +INSERT INTO t1 VALUES (1,1,1,1,1,1,1), (2,2,2,2,2,2,2); +INSERT INTO t1 VALUES (null, 5, null, null, null, null, null); +INSERT INTO t1 VALUES (3,3,3,3,3,3,3), (4,4,4,4,4,4,4); +INSERT INTO t1 VALUES (null, 7, null, null, null, null, null); +INSERT INTO t1 VALUES (8,8,127,255,8,8,8); +INSERT INTO t1 VALUES (6,6,6,6,6,6,6), (7,7,7,7,7,7,7); +INSERT INTO t1 VALUES (8,8,8,8,8,8,8), (6,2,3,9,8,4,1); +INSERT INTO t1 VALUES (-1, -2, -4, 8, -16, -32, -20); +select * from t1; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +NULL 5 NULL NULL NULL NULL NULL +3 3 3 3 3 3 3 +4 4 4 4 4 4 4 +NULL 7 NULL NULL NULL NULL NULL +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +7 7 7 7 7 7 7 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +select * from t1 where c1 % 2 = 0; +c1 c2 c3 c4 c5 c6 c7 +2 2 2 2 2 2 2 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +select * from t1 where c2 % 2 = 0; +c1 c2 c3 c4 c5 c6 c7 +2 2 2 2 2 2 2 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +select * from t1 where c3 % 2 = 0; +c1 c2 c3 c4 c5 c6 c7 +2 2 2 2 2 2 2 +4 4 4 4 4 4 4 +6 6 6 6 6 6 6 +8 8 8 8 8 8 8 +-1 -2 -4 8 -16 -32 -20 +select * from t1 where c4 % 2 = 0; +c1 c2 c3 c4 c5 c6 c7 +2 2 2 2 2 2 2 +4 4 4 4 4 4 4 +6 6 6 6 6 6 6 +8 8 8 8 8 8 8 +-1 -2 -4 8 -16 -32 -20 +select * from t1 where c5 % 2 = 0; +c1 c2 c3 c4 c5 c6 c7 +2 2 2 2 2 2 2 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +select * from t1 where c6 % 2 = 0; +c1 c2 c3 c4 c5 c6 c7 +2 2 2 2 2 2 2 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +select * from t1 where c7 % 2 = 0; +c1 c2 c3 c4 c5 c6 c7 +2 2 2 2 2 2 2 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +8 8 8 8 8 8 8 +-1 -2 -4 8 -16 -32 -20 +select * from t1 where 2 % c1 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +-1 -2 -4 8 -16 -32 -20 +select * from t1 where 2 % c2 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +select * from t1 where 2 % c3 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +select * from t1 where 2 % c4 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +select * from t1 where 2 % c5 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +select * from t1 where 2 % c6 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +select * from t1 where 2 % c7 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +6 2 3 9 8 4 1 +select * from t1 where 3 % c1 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +3 3 3 3 3 3 3 +-1 -2 -4 8 -16 -32 -20 +select * from t1 where 3 % c2 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +3 3 3 3 3 3 3 +select * from t1 where 3 % c3 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +3 3 3 3 3 3 3 +6 2 3 9 8 4 1 +select * from t1 where 3 % c4 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +3 3 3 3 3 3 3 +select * from t1 where 3 % c5 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +3 3 3 3 3 3 3 +select * from t1 where 3 % c6 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +3 3 3 3 3 3 3 +select * from t1 where 3 % c7 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +3 3 3 3 3 3 3 +6 2 3 9 8 4 1 +select * from t1 where 3 % c1 = c1 % 3; +c1 c2 c3 c4 c5 c6 c7 +3 3 3 3 3 3 3 +select * from t1 where 9 % c2 = 3 % c2; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +3 3 3 3 3 3 3 +6 6 6 6 6 6 6 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +select * from t1 where 3 % c3 = 2 / 3; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 3 % c4 = 1 * 2; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 3 % c5 = c2 + c7; +c1 c2 c3 c4 c5 c6 c7 +6 2 3 9 8 4 1 +select * from t1 where 3 % c6 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +3 3 3 3 3 3 3 +select * from t1 where 3 % c7 = 0; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +3 3 3 3 3 3 3 +6 2 3 9 8 4 1 +select * from t1 where c1 / 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +2 2 2 2 2 2 2 +select * from t1 where c2 / 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +2 2 2 2 2 2 2 +6 2 3 9 8 4 1 +select * from t1 where c3 / 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +2 2 2 2 2 2 2 +select * from t1 where c4 / 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +2 2 2 2 2 2 2 +select * from t1 where c5 / 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +2 2 2 2 2 2 2 +select * from t1 where c6 / 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +2 2 2 2 2 2 2 +select * from t1 where c7 / 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +2 2 2 2 2 2 2 +select * from t1 where c1 / 0 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +select * from t1 where c2 / 0 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +select * from t1 where c3 / 0 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +select * from t1 where c4 / 0 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +select * from t1 where c5 / 0 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +select * from t1 where c6 / 0 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +select * from t1 where c7 / 0 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +select * from t1 where 0 / c1 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 0 / c2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 0 / c3 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 0 / c4 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 0 / c5 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 0 / c6 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 0 / c7 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where c1 / c2 = c3 * c7; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +6 2 3 9 8 4 1 +select * from t1 where c1 / c2 = c3; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +6 2 3 9 8 4 1 +INSERT INTO t1 VALUES (0,0,0,0,0,0,0); +select * from t1 where c1 / 0 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +select * from t1 where c2 / 0 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +select * from t1 where c3 / 0 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +select * from t1 where c4 / 0 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +select * from t1 where c5 / 0 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +select * from t1 where c6 / 0 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +select * from t1 where c7 / 0 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +select * from t1 where 0 / c1 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +select * from t1 where 0 / c2 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +select * from t1 where 0 / c3 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +select * from t1 where 0 / c4 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +select * from t1 where 0 / c5 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +select * from t1 where 0 / c6 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +select * from t1 where 0 / c7 = 1; +c1 c2 c3 c4 c5 c6 c7 +Warnings: +Warning 1365 Division by 0 +select * from t1 where c1 * 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where c2 * 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where c3 * 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where c4 * 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where c5 * 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where c6 * 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where c7 * 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 2 * c1 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 2 * c2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 2 * c3 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 2 * c4 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 2 * c5 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 2 * c6 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 2 * c7 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where 2 * c1 = c1 * 2; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +3 3 3 3 3 3 3 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +7 7 7 7 7 7 7 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +0 0 0 0 0 0 0 +select * from t1 where 2 * c2 = c2 * 2; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +NULL 5 NULL NULL NULL NULL NULL +3 3 3 3 3 3 3 +4 4 4 4 4 4 4 +NULL 7 NULL NULL NULL NULL NULL +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +7 7 7 7 7 7 7 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +0 0 0 0 0 0 0 +select * from t1 where 2 * c3 = c3 * 2; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +3 3 3 3 3 3 3 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +7 7 7 7 7 7 7 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +0 0 0 0 0 0 0 +select * from t1 where 2 * c4 = c4 * 2; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +3 3 3 3 3 3 3 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +7 7 7 7 7 7 7 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +0 0 0 0 0 0 0 +select * from t1 where 2 * c5 = c5 * 2; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +3 3 3 3 3 3 3 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +7 7 7 7 7 7 7 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +0 0 0 0 0 0 0 +select * from t1 where 2 * c6 = c6 * 2; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +3 3 3 3 3 3 3 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +7 7 7 7 7 7 7 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +0 0 0 0 0 0 0 +select * from t1 where 2 * c7 = c7 * 2; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +3 3 3 3 3 3 3 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +7 7 7 7 7 7 7 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +0 0 0 0 0 0 0 +select * from t1 where 2 * c1 = c1 * 2 * 1; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +3 3 3 3 3 3 3 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +7 7 7 7 7 7 7 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +0 0 0 0 0 0 0 +select * from t1 where 2 * c2 = c2 * 2 / 1; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +NULL 5 NULL NULL NULL NULL NULL +3 3 3 3 3 3 3 +4 4 4 4 4 4 4 +NULL 7 NULL NULL NULL NULL NULL +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +7 7 7 7 7 7 7 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +0 0 0 0 0 0 0 +select * from t1 where 2 * c3 = c3 * 2 / 2 * 2; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +3 3 3 3 3 3 3 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +7 7 7 7 7 7 7 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +0 0 0 0 0 0 0 +select * from t1 where 2 * c4 = c4 * 2 / 3 * 3; +c1 c2 c3 c4 c5 c6 c7 +3 3 3 3 3 3 3 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +6 2 3 9 8 4 1 +0 0 0 0 0 0 0 +select * from t1 where 2 * c5 = c5 * 2 / 3 * 2; +c1 c2 c3 c4 c5 c6 c7 +0 0 0 0 0 0 0 +select * from t1 where 2 * c6 = c6 * 2 / 4 * 2; +c1 c2 c3 c4 c5 c6 c7 +0 0 0 0 0 0 0 +select * from t1 where 2 * c7 = c7 * 2; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +3 3 3 3 3 3 3 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +7 7 7 7 7 7 7 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +0 0 0 0 0 0 0 +select * from t1 where c1 / 2 = c2 / 2; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +3 3 3 3 3 3 3 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +7 7 7 7 7 7 7 +8 8 8 8 8 8 8 +0 0 0 0 0 0 0 +select * from t1 where c1 / 3 = c2 * 3; +c1 c2 c3 c4 c5 c6 c7 +0 0 0 0 0 0 0 +select * from t1 where c1 * c2 = c3 * c6; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +3 3 3 3 3 3 3 +4 4 4 4 4 4 4 +6 6 6 6 6 6 6 +7 7 7 7 7 7 7 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +0 0 0 0 0 0 0 +select * from t1 where c1 * c2 = c3 * c6 * c7; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +6 2 3 9 8 4 1 +0 0 0 0 0 0 0 +select * from t1 where c1 + 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +-1 -2 -4 8 -16 -32 -20 +select * from t1 where c2 + 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where c3 + 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where c4 + 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where c5 + 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where c6 + 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where c7 + 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select c1 + 2 + 2 from t1; +c1 + 2 + 2 +5 +6 +NULL +7 +8 +NULL +12 +10 +11 +12 +10 +3 +4 +select * from t1 where c1 + 2 + 2 = 4; +c1 c2 c3 c4 c5 c6 c7 +0 0 0 0 0 0 0 +select c2 + 2 * 2 from t1; +c2 + 2 * 2 +5 +6 +9 +7 +8 +11 +12 +10 +11 +12 +6 +2 +4 +select * from t1 where c2 + 2 * 2 = 8; +c1 c2 c3 c4 c5 c6 c7 +4 4 4 4 4 4 4 +select c3 + 2 / 3 from t1; +c3 + 2 / 3 +1.6667 +2.6667 +NULL +3.6667 +4.6667 +NULL +127.6667 +6.6667 +7.6667 +8.6667 +3.6667 +-3.3333 +0.6667 +select * from t1 where c3 + 2 / 3 = 1; +c1 c2 c3 c4 c5 c6 c7 +select c4 + 2 / 4 from t1; +c4 + 2 / 4 +1.5000 +2.5000 +NULL +3.5000 +4.5000 +NULL +255.5000 +6.5000 +7.5000 +8.5000 +9.5000 +8.5000 +0.5000 +select * from t1 where c4 + 2 / 4 = 1; +c1 c2 c3 c4 c5 c6 c7 +select c5 + 4 / 2 from t1; +c5 + 4 / 2 +3.0000 +4.0000 +NULL +5.0000 +6.0000 +NULL +10.0000 +8.0000 +9.0000 +10.0000 +10.0000 +-14.0000 +2.0000 +select * from t1 where c5 + 4 / 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +select c5 + 4 / 2 from t1; +c5 + 4 / 2 +3.0000 +4.0000 +NULL +5.0000 +6.0000 +NULL +10.0000 +8.0000 +9.0000 +10.0000 +10.0000 +-14.0000 +2.0000 +select * from t1 where c6 + 2 * c7 = 6; +c1 c2 c3 c4 c5 c6 c7 +2 2 2 2 2 2 2 +6 2 3 9 8 4 1 +select * from t1 where 2 + c7 = -1; +c1 c2 c3 c4 c5 c6 c7 +select * from t1 where c1 - 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +3 3 3 3 3 3 3 +select * from t1 where c2 - 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +3 3 3 3 3 3 3 +select * from t1 where c3 - 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +3 3 3 3 3 3 3 +6 2 3 9 8 4 1 +select * from t1 where c4 - 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +3 3 3 3 3 3 3 +select * from t1 where c5 - 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +3 3 3 3 3 3 3 +select * from t1 where c6 - 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +3 3 3 3 3 3 3 +select * from t1 where c7 - 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +3 3 3 3 3 3 3 +select * from t1 where 4 - c4 = 4 - c4; +ERROR 22003: BIGINT UNSIGNED value is out of range in '(4 - `test`.`t1`.`c4`)' +select * from t1 where c4 - c1 = c4 - c1; +c1 c2 c3 c4 c5 c6 c7 +1 1 1 1 1 1 1 +2 2 2 2 2 2 2 +3 3 3 3 3 3 3 +4 4 4 4 4 4 4 +8 8 127 255 8 8 8 +6 6 6 6 6 6 6 +7 7 7 7 7 7 7 +8 8 8 8 8 8 8 +6 2 3 9 8 4 1 +-1 -2 -4 8 -16 -32 -20 +0 0 0 0 0 0 0 +select * from t1 where c3 - 2 = 1; +c1 c2 c3 c4 c5 c6 c7 +3 3 3 3 3 3 3 +6 2 3 9 8 4 1 +create table t16 (a int, b int unsigned); +insert into t16 values (1,2),(2,1),(NULL,NULL),(1,NULL),(NULL,1); +select * from t16; +a b +1 2 +2 1 +NULL NULL +1 NULL +NULL 1 +select * from t16 where -a < 0; +a b +1 2 +2 1 +1 NULL +select * from t16 where a - '2' >= 0; +a b +2 1 +select * from t16 where a % 0 = 0; +a b +select * from t16 where a / 0 = 0; +a b +Warnings: +Warning 1365 Division by 0 +Warning 1365 Division by 0 +Warning 1365 Division by 0 +select * from t16 where a + 9223372036854775807 > 0; +ERROR 22003: BIGINT value is out of range in '(`test`.`t16`.`a` + 9223372036854775807)' +select * from t16 where a + 9223372036854775808 > 0; +a b +1 2 +2 1 +1 NULL +select * from t16 where a + 18446744073709551615 > 0; +ERROR 22003: BIGINT UNSIGNED value is out of range in '(`test`.`t16`.`a` + 18446744073709551615)' +select * from t16 where a + 18446744073709551616 > 0; +a b +1 2 +2 1 +1 NULL +select * from t16 where a > 1; +a b +2 1 +select * from t16 where a >= 1; +a b +1 2 +2 1 +1 NULL +select * from t16 where a < 2; +a b +1 2 +1 NULL +select * from t16 where a <= 2; +a b +1 2 +2 1 +1 NULL +select * from t16 where a; +a b +1 2 +2 1 +1 NULL +select * from t16 where a <> 0; +a b +1 2 +2 1 +1 NULL +select * from t16 where a != 0; +a b +1 2 +2 1 +1 NULL +select * from t16 where !a; +a b +Warnings: +Warning 1287 '!' is deprecated and will be removed in a future release. Please use NOT instead +select * from t16 where NOT a; +a b +select * from t16 where NOT NOT a; +a b +1 2 +2 1 +1 NULL +select * from t16 where a <> NULL; +a b +select * from t16 where a != NULL; +a b +select * from t16 where a <=> 2; +a b +2 1 +select * from t16 where a <=> NULL; +a b +NULL NULL +NULL 1 +select * from t16 where a = 2; +a b +2 1 +select * from t16 where a = NULL; +a b +select * from t16 where a is true; +a b +1 2 +2 1 +1 NULL +select * from t16 where a is NOT true; +a b +NULL NULL +NULL 1 +select * from t16 where a like 1; +a b +1 2 +1 NULL +select * from t16 where a not like 1; +a b +2 1 +select * from t16 where a like NULL; +a b +select * from t16 where a NOT like NULL; +a b +select * from t16 where a + b > 1; +a b +1 2 +2 1 +select * from t16 where 1 < a; +a b +2 1 +select * from t16 where a - 1; +a b +2 1 +select * from t16 where a - 2; +a b +1 2 +1 NULL +select * from t16 where (a > 1) and (b > 1); +a b +select * from t16 where (a > 1) && (b > 1); +a b +Warnings: +Warning 1287 '&&' is deprecated and will be removed in a future release. Please use AND instead +select * from t16 where (a > 1) or (b > 1); +a b +1 2 +2 1 +select * from t16 where (a > 1) || (b > 1); +a b +1 2 +2 1 +Warnings: +Warning 1287 '|| as a synonym for OR' is deprecated and will be removed in a future release. Please use OR instead +select * from t16 where ((a > 1) and (b > 1)) < 1; +a b +1 2 +2 1 +1 NULL +NULL 1 +select * from t16 where ((a > 1) + (b > 1)) > 1; +a b +select * from t16 where ((a > 1) XOR (b > 1)) < 1; +a b +select * from t16 where a = 2 is null; +a b +NULL NULL +NULL 1 +select * from t16 where a = 2 = null; +a b +select * from t16 where a <=> NULL = 1; +a b +NULL NULL +NULL 1 +select * from t16 where a + (-2) >= 0; +a b +2 1 +create table t17 (a int, b int GENERATED ALWAYS AS (a + 1)); +insert into t17(a) values (NULL),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +select * from t17 where a > 1; +a b +2 3 +3 4 +4 5 +5 6 +6 7 +7 8 +8 9 +9 10 +10 11 +select * from t17 where b > 1; +a b +1 2 +2 3 +3 4 +4 5 +5 6 +6 7 +7 8 +8 9 +9 10 +10 11 +select * from t17 where (a > 1) AND (b > 1); +a b +2 3 +3 4 +4 5 +5 6 +6 7 +7 8 +8 9 +9 10 +10 11 +select * from t17 where (a > 1) OR (b > 1); +a b +1 2 +2 3 +3 4 +4 5 +5 6 +6 7 +7 8 +8 9 +9 10 +10 11 +select * from t17 where ((a > 1) AND (b > 1)) = 1; +a b +2 3 +3 4 +4 5 +5 6 +6 7 +7 8 +8 9 +9 10 +10 11 +select * from t17 where ((a > 1) OR (b > 1)) = 1; +a b +1 2 +2 3 +3 4 +4 5 +5 6 +6 7 +7 8 +8 9 +9 10 +10 11 +select * from t17 where (a < 5) AND (a > 1) AND (b > 1); +a b +2 3 +3 4 +4 5 +select * from t17 where (a < 5) AND (a > 1) OR (b > 1); +a b +1 2 +2 3 +3 4 +4 5 +5 6 +6 7 +7 8 +8 9 +9 10 +10 11 +select * from t17 where (a < 5) AND ((a > 1) OR (b > 1)); +a b +1 2 +2 3 +3 4 +4 5 +select * from t17 where (a < 2) OR (a > 8) OR (b > 1); +a b +1 2 +2 3 +3 4 +4 5 +5 6 +6 7 +7 8 +8 9 +9 10 +10 11 +select * from t17 where (a < 2) OR (a > 8) AND (b > 1); +a b +1 2 +9 10 +10 11 +select * from t17 where ((a < 2) OR (a > 8)) AND (b > 1); +a b +1 2 +9 10 +10 11 +select * from t17 where (a < 2) OR ((a > 8) OR (b > 1)); +a b +1 2 +2 3 +3 4 +4 5 +5 6 +6 7 +7 8 +8 9 +9 10 +10 11 +CREATE TABLE t18(c1 int, c2 int, key(c1,c2)); +INSERT INTO t18 VALUES (94,94),(64,64),(69,69),(97,97); +select * from t18; +c1 c2 +64 64 +69 69 +94 94 +97 97 drop table t1; drop table t2; drop table t3; @@ -678,3 +2036,27 @@ drop table t12; drop table t13; drop table t14; drop table t15; +drop table t16; +drop table t17; +drop table t18; +create table tb_cache(a int); +insert into tb_cache values(null); +insert into tb_cache values(1); +insert into tb_cache values(0); +prepare stmt1 from 'select a from tb_cache where a <=> ?'; +set @arg1 = null; +execute stmt1 using @arg1; +a +NULL +set @arg2 = 1; +execute stmt1 using @arg2; +a +1 +set @arg3 = 'a'; +execute stmt1 using @arg3; +a +0 +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'a' +Warning 1292 Truncated incorrect INTEGER value: 'a' +drop table tb_cache; diff --git a/mysql-test/suite/ctc/r/ctc_cond_pushdown_explain.result b/mysql-test/suite/ctc/r/ctc_cond_pushdown_explain.result index 060d057..182a8a1 100644 --- a/mysql-test/suite/ctc/r/ctc_cond_pushdown_explain.result +++ b/mysql-test/suite/ctc/r/ctc_cond_pushdown_explain.result @@ -280,7 +280,7 @@ c1 c2 c3 c4 c5 2023 23:59:59 2012-01-01 2015-05-29 13:13:13 2020-03-04 11:21:14 explain select * from t5 where c2 > '23:59:50'; id select_type table partitions type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t5 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`t5`.`c2` > TIME'23:59:50') +1 SIMPLE t5 NULL ALL NULL NULL NULL NULL 3 33.33 Using where select * from t5 where c3 < '2012-01-01'; c1 c2 c3 c4 c5 1994 23:59:59 2000-01-01 2008-02-29 13:13:13 2012-03-04 11:21:14 @@ -366,3 +366,987 @@ explain select * from t7 where c4 != -39; id select_type table partitions type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t7 NULL ALL NULL NULL NULL NULL 3 66.67 Using where; Using pushed condition (`test`.`t7`.`c4` <> (-(39))) drop table t1, t2, t3, t4, t5, t6, t7; +CREATE TABLE t1(c1 tinyint, c2 tinyint not null, c3 tinyint signed, c4 tinyint unsigned, c5 int, c6 long, c7 bigint); +INSERT INTO t1 VALUES (1,1,1,1,1,1,1), (2,2,2,2,2,2,2); +INSERT INTO t1 VALUES (null, 5, null, null, null, null, null); +INSERT INTO t1 VALUES (3,3,3,3,3,3,3), (4,4,4,4,4,4,4); +INSERT INTO t1 VALUES (null, 7, null, null, null, null, null); +INSERT INTO t1 VALUES (8,8,127,255,8,8,8); +INSERT INTO t1 VALUES (6,6,6,6,6,6,6), (7,7,7,7,7,7,7); +INSERT INTO t1 VALUES (8,8,8,8,8,8,8), (6,2,3,9,8,4,1); +INSERT INTO t1 VALUES (-1, -2, -4, 8, -16, -32, -20); +explain select * from t1 where c1 % 2 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c1` % 2) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c1` % 2) = 0) +explain select * from t1 where c2 % 2 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c2` % 2) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c2` % 2) = 0) +explain select * from t1 where c3 % 2 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c3` % 2) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c3` % 2) = 0) +explain select * from t1 where c4 % 2 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c4` % 2) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c4` % 2) = 0) +explain select * from t1 where c5 % 2 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c5` % 2) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c5` % 2) = 0) +explain select * from t1 where c6 % 2 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c6` % 2) = 0) +explain select * from t1 where c7 % 2 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c7` % 2) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c7` % 2) = 0) +explain select * from t1 where 2 % c1 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 % `test`.`t1`.`c1`) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 % `test`.`t1`.`c1`) = 0) +explain select * from t1 where 2 % c2 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 % `test`.`t1`.`c2`) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 % `test`.`t1`.`c2`) = 0) +explain select * from t1 where 2 % c3 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 % `test`.`t1`.`c3`) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 % `test`.`t1`.`c3`) = 0) +explain select * from t1 where 2 % c4 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 % `test`.`t1`.`c4`) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 % `test`.`t1`.`c4`) = 0) +explain select * from t1 where 2 % c5 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 % `test`.`t1`.`c5`) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 % `test`.`t1`.`c5`) = 0) +explain select * from t1 where 2 % c6 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 % `test`.`t1`.`c6`) = 0) +explain select * from t1 where 2 % c7 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 % `test`.`t1`.`c7`) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 % `test`.`t1`.`c7`) = 0) +explain select * from t1 where 3 % c1 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((3 % `test`.`t1`.`c1`) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((3 % `test`.`t1`.`c1`) = 0) +explain select * from t1 where 3 % c2 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((3 % `test`.`t1`.`c2`) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((3 % `test`.`t1`.`c2`) = 0) +explain select * from t1 where 3 % c3 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((3 % `test`.`t1`.`c3`) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((3 % `test`.`t1`.`c3`) = 0) +explain select * from t1 where 3 % c4 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((3 % `test`.`t1`.`c4`) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((3 % `test`.`t1`.`c4`) = 0) +explain select * from t1 where 3 % c5 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((3 % `test`.`t1`.`c5`) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((3 % `test`.`t1`.`c5`) = 0) +explain select * from t1 where 3 % c6 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((3 % `test`.`t1`.`c6`) = 0) +explain select * from t1 where 3 % c7 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((3 % `test`.`t1`.`c7`) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((3 % `test`.`t1`.`c7`) = 0) +explain select * from t1 where 3 % c1 = c1 % 3; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((3 % `test`.`t1`.`c1`) = (`test`.`t1`.`c1` % 3)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((3 % `test`.`t1`.`c1`) = (`test`.`t1`.`c1` % 3)) +explain select * from t1 where 9 % c2 = 3 % c2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((9 % `test`.`t1`.`c2`) = (3 % `test`.`t1`.`c2`)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((9 % `test`.`t1`.`c2`) = (3 % `test`.`t1`.`c2`)) +explain select * from t1 where 3 % c3 = 2 / 3; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((3 % `test`.`t1`.`c3`) = ((2 / 3))) +explain select * from t1 where 3 % c4 = 1 * 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((3 % `test`.`t1`.`c4`) = ((1 * 2))) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((3 % `test`.`t1`.`c4`) = ((1 * 2))) +explain select * from t1 where 3 % c5 = c2 + c7; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((3 % `test`.`t1`.`c5`) = (`test`.`t1`.`c2` + `test`.`t1`.`c7`)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((3 % `test`.`t1`.`c5`) = (`test`.`t1`.`c2` + `test`.`t1`.`c7`)) +explain select * from t1 where 3 % c6 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((3 % `test`.`t1`.`c6`) = 0) +explain select * from t1 where 3 % c7 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((3 % `test`.`t1`.`c7`) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((3 % `test`.`t1`.`c7`) = 0) +explain select * from t1 where c1 / 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c1` / 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c1` / 2) = 1) +explain select * from t1 where c2 / 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c2` / 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c2` / 2) = 1) +explain select * from t1 where c3 / 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c3` / 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c3` / 2) = 1) +explain select * from t1 where c4 / 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c4` / 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c4` / 2) = 1) +explain select * from t1 where c5 / 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c5` / 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c5` / 2) = 1) +explain select * from t1 where c6 / 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c6` / 2) = 1) +explain select * from t1 where c7 / 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c7` / 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c7` / 2) = 1) +explain select * from t1 where c1 / 0 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c1` / 0) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c1` / 0) = 1) +explain select * from t1 where c2 / 0 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c2` / 0) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c2` / 0) = 1) +explain select * from t1 where c3 / 0 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c3` / 0) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c3` / 0) = 1) +explain select * from t1 where c4 / 0 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c4` / 0) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c4` / 0) = 1) +explain select * from t1 where c5 / 0 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c5` / 0) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c5` / 0) = 1) +explain select * from t1 where c6 / 0 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c6` / 0) = 1) +explain select * from t1 where c7 / 0 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c7` / 0) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c7` / 0) = 1) +explain select * from t1 where 0 / c1 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((0 / `test`.`t1`.`c1`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((0 / `test`.`t1`.`c1`) = 1) +explain select * from t1 where 0 / c2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((0 / `test`.`t1`.`c2`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((0 / `test`.`t1`.`c2`) = 1) +explain select * from t1 where 0 / c3 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((0 / `test`.`t1`.`c3`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((0 / `test`.`t1`.`c3`) = 1) +explain select * from t1 where 0 / c4 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((0 / `test`.`t1`.`c4`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((0 / `test`.`t1`.`c4`) = 1) +explain select * from t1 where 0 / c5 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((0 / `test`.`t1`.`c5`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((0 / `test`.`t1`.`c5`) = 1) +explain select * from t1 where 0 / c6 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((0 / `test`.`t1`.`c6`) = 1) +explain select * from t1 where 0 / c7 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((0 / `test`.`t1`.`c7`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((0 / `test`.`t1`.`c7`) = 1) +explain select * from t1 where c1 / c2 = c3 * c7; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c1` / `test`.`t1`.`c2`) = (`test`.`t1`.`c3` * `test`.`t1`.`c7`)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c1` / `test`.`t1`.`c2`) = (`test`.`t1`.`c3` * `test`.`t1`.`c7`)) +explain select * from t1 where c1 / c2 = c3; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition ((`test`.`t1`.`c1` / `test`.`t1`.`c2`) = `test`.`t1`.`c3`) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c1` / `test`.`t1`.`c2`) = `test`.`t1`.`c3`) +INSERT INTO t1 VALUES (0,0,0,0,0,0,0); +explain select * from t1 where c1 / 0 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c1` / 0) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c1` / 0) = 1) +explain select * from t1 where c2 / 0 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c2` / 0) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c2` / 0) = 1) +explain select * from t1 where c3 / 0 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c3` / 0) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c3` / 0) = 1) +explain select * from t1 where c4 / 0 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c4` / 0) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c4` / 0) = 1) +explain select * from t1 where c5 / 0 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c5` / 0) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c5` / 0) = 1) +explain select * from t1 where c6 / 0 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c6` / 0) = 1) +explain select * from t1 where c7 / 0 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c7` / 0) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c7` / 0) = 1) +explain select * from t1 where 0 / c1 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((0 / `test`.`t1`.`c1`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((0 / `test`.`t1`.`c1`) = 1) +explain select * from t1 where 0 / c2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((0 / `test`.`t1`.`c2`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((0 / `test`.`t1`.`c2`) = 1) +explain select * from t1 where 0 / c3 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((0 / `test`.`t1`.`c3`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((0 / `test`.`t1`.`c3`) = 1) +explain select * from t1 where 0 / c4 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((0 / `test`.`t1`.`c4`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((0 / `test`.`t1`.`c4`) = 1) +explain select * from t1 where 0 / c5 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((0 / `test`.`t1`.`c5`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((0 / `test`.`t1`.`c5`) = 1) +explain select * from t1 where 0 / c6 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((0 / `test`.`t1`.`c6`) = 1) +explain select * from t1 where 0 / c7 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((0 / `test`.`t1`.`c7`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((0 / `test`.`t1`.`c7`) = 1) +explain select * from t1 where c1 * 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c1` * 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c1` * 2) = 1) +explain select * from t1 where c2 * 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c2` * 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c2` * 2) = 1) +explain select * from t1 where c3 * 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c3` * 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c3` * 2) = 1) +explain select * from t1 where c4 * 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c4` * 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c4` * 2) = 1) +explain select * from t1 where c5 * 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c5` * 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c5` * 2) = 1) +explain select * from t1 where c6 * 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c6` * 2) = 1) +explain select * from t1 where c7 * 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c7` * 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c7` * 2) = 1) +explain select * from t1 where 2 * c1 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c1`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c1`) = 1) +explain select * from t1 where 2 * c2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c2`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c2`) = 1) +explain select * from t1 where 2 * c3 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c3`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c3`) = 1) +explain select * from t1 where 2 * c4 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c4`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c4`) = 1) +explain select * from t1 where 2 * c5 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c5`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c5`) = 1) +explain select * from t1 where 2 * c6 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c6`) = 1) +explain select * from t1 where 2 * c7 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c7`) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c7`) = 1) +explain select * from t1 where 2 * c1 = c1 * 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c1`) = (`test`.`t1`.`c1` * 2)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c1`) = (`test`.`t1`.`c1` * 2)) +explain select * from t1 where 2 * c2 = c2 * 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c2`) = (`test`.`t1`.`c2` * 2)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c2`) = (`test`.`t1`.`c2` * 2)) +explain select * from t1 where 2 * c3 = c3 * 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c3`) = (`test`.`t1`.`c3` * 2)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c3`) = (`test`.`t1`.`c3` * 2)) +explain select * from t1 where 2 * c4 = c4 * 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c4`) = (`test`.`t1`.`c4` * 2)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c4`) = (`test`.`t1`.`c4` * 2)) +explain select * from t1 where 2 * c5 = c5 * 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c5`) = (`test`.`t1`.`c5` * 2)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c5`) = (`test`.`t1`.`c5` * 2)) +explain select * from t1 where 2 * c6 = c6 * 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c6`) = (`test`.`t1`.`c6` * 2)) +explain select * from t1 where 2 * c7 = c7 * 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c7`) = (`test`.`t1`.`c7` * 2)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c7`) = (`test`.`t1`.`c7` * 2)) +explain select * from t1 where 2 * c1 = c1 * 2 * 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c1`) = ((`test`.`t1`.`c1` * 2) * 1)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c1`) = ((`test`.`t1`.`c1` * 2) * 1)) +explain select * from t1 where 2 * c2 = c2 * 2 / 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c2`) = ((`test`.`t1`.`c2` * 2) / 1)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c2`) = ((`test`.`t1`.`c2` * 2) / 1)) +explain select * from t1 where 2 * c3 = c3 * 2 / 2 * 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c3`) = (((`test`.`t1`.`c3` * 2) / 2) * 2)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c3`) = (((`test`.`t1`.`c3` * 2) / 2) * 2)) +explain select * from t1 where 2 * c4 = c4 * 2 / 3 * 3; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c4`) = (((`test`.`t1`.`c4` * 2) / 3) * 3)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c4`) = (((`test`.`t1`.`c4` * 2) / 3) * 3)) +explain select * from t1 where 2 * c5 = c5 * 2 / 3 * 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c5`) = (((`test`.`t1`.`c5` * 2) / 3) * 2)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c5`) = (((`test`.`t1`.`c5` * 2) / 3) * 2)) +explain select * from t1 where 2 * c6 = c6 * 2 / 4 * 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c6`) = (((`test`.`t1`.`c6` * 2) / 4) * 2)) +explain select * from t1 where 2 * c7 = c7 * 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 * `test`.`t1`.`c7`) = (`test`.`t1`.`c7` * 2)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 * `test`.`t1`.`c7`) = (`test`.`t1`.`c7` * 2)) +explain select * from t1 where c1 / 2 = c2 / 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c1` / 2) = (`test`.`t1`.`c2` / 2)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c1` / 2) = (`test`.`t1`.`c2` / 2)) +explain select * from t1 where c1 / 3 = c2 * 3; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c1` / 3) = (`test`.`t1`.`c2` * 3)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c1` / 3) = (`test`.`t1`.`c2` * 3)) +explain select * from t1 where c1 * c2 = c3 * c6; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c1` * `test`.`t1`.`c2`) = (`test`.`t1`.`c3` * `test`.`t1`.`c6`)) +explain select * from t1 where c1 * c2 = c3 * c6 * c7; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c1` * `test`.`t1`.`c2`) = ((`test`.`t1`.`c3` * `test`.`t1`.`c6`) * `test`.`t1`.`c7`)) +explain select * from t1 where c1 + 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c1` + 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c1` + 2) = 1) +explain select * from t1 where c2 + 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c2` + 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c2` + 2) = 1) +explain select * from t1 where c3 + 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c3` + 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c3` + 2) = 1) +explain select * from t1 where c4 + 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c4` + 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c4` + 2) = 1) +explain select * from t1 where c5 + 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c5` + 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c5` + 2) = 1) +explain select * from t1 where c6 + 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c6` + 2) = 1) +explain select * from t1 where c7 + 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c7` + 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c7` + 2) = 1) +explain select c1 + 2 + 2 from t1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 NULL +Warnings: +Note 1003 /* select#1 */ select ((`test`.`t1`.`c1` + 2) + 2) AS `c1 + 2 + 2` from `test`.`t1` +explain select * from t1 where c1 + 2 + 2 = 4; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition (((`test`.`t1`.`c1` + 2) + 2) = 4) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where (((`test`.`t1`.`c1` + 2) + 2) = 4) +explain select c2 + 2 * 2 from t1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 NULL +Warnings: +Note 1003 /* select#1 */ select (`test`.`t1`.`c2` + (2 * 2)) AS `c2 + 2 * 2` from `test`.`t1` +explain select * from t1 where c2 + 2 * 2 = 8; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c2` + ((2 * 2))) = 8) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c2` + ((2 * 2))) = 8) +explain select c3 + 2 / 3 from t1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 NULL +Warnings: +Note 1003 /* select#1 */ select (`test`.`t1`.`c3` + (2 / 3)) AS `c3 + 2 / 3` from `test`.`t1` +explain select * from t1 where c3 + 2 / 3 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c3` + ((2 / 3))) = 1) +explain select c4 + 2 / 4 from t1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 NULL +Warnings: +Note 1003 /* select#1 */ select (`test`.`t1`.`c4` + (2 / 4)) AS `c4 + 2 / 4` from `test`.`t1` +explain select * from t1 where c4 + 2 / 4 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c4` + ((2 / 4))) = 1) +explain select c5 + 4 / 2 from t1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 NULL +Warnings: +Note 1003 /* select#1 */ select (`test`.`t1`.`c5` + (4 / 2)) AS `c5 + 4 / 2` from `test`.`t1` +explain select * from t1 where c5 + 4 / 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c5` + ((4 / 2))) = 1) +explain select c5 + 4 / 2 from t1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 NULL +Warnings: +Note 1003 /* select#1 */ select (`test`.`t1`.`c5` + (4 / 2)) AS `c5 + 4 / 2` from `test`.`t1` +explain select * from t1 where c6 + 2 * c7 = 6; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c6` + (2 * `test`.`t1`.`c7`)) = 6) +explain select * from t1 where 2 + c7 = -1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((2 + `test`.`t1`.`c7`) = (-(1))) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((2 + `test`.`t1`.`c7`) = (-(1))) +explain select * from t1 where c1 - 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c1` - 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c1` - 2) = 1) +explain select * from t1 where c2 - 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c2` - 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c2` - 2) = 1) +explain select * from t1 where c3 - 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c3` - 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c3` - 2) = 1) +explain select * from t1 where c4 - 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c4` - 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c4` - 2) = 1) +explain select * from t1 where c5 - 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c5` - 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c5` - 2) = 1) +explain select * from t1 where c6 - 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c6` - 2) = 1) +explain select * from t1 where c7 - 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c7` - 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c7` - 2) = 1) +explain select * from t1 where 4 - c4 = 4 - c4; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((4 - `test`.`t1`.`c4`) = (4 - `test`.`t1`.`c4`)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((4 - `test`.`t1`.`c4`) = (4 - `test`.`t1`.`c4`)) +explain select * from t1 where c4 - c1 = c4 - c1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c4` - `test`.`t1`.`c1`) = (`test`.`t1`.`c4` - `test`.`t1`.`c1`)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c4` - `test`.`t1`.`c1`) = (`test`.`t1`.`c4` - `test`.`t1`.`c1`)) +explain select * from t1 where c3 - 2 = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t1`.`c3` - 2) = 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t1`.`c1` AS `c1`,`test`.`t1`.`c2` AS `c2`,`test`.`t1`.`c3` AS `c3`,`test`.`t1`.`c4` AS `c4`,`test`.`t1`.`c5` AS `c5`,`test`.`t1`.`c6` AS `c6`,`test`.`t1`.`c7` AS `c7` from `test`.`t1` where ((`test`.`t1`.`c3` - 2) = 1) +create table t16 (a int, b int unsigned); +insert into t16 values (1,2),(2,1),(NULL,NULL),(1,NULL),(NULL,1); +explain select * from t16; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 NULL +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` +explain select * from t16 where -a < 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (-(`test`.`t16`.`a`) < 0) +explain select * from t16 where a - '2' >= 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` - '2') >= 0) +explain select * from t16 where a % 0 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t16`.`a` % 0) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` % 0) = 0) +explain select * from t16 where a / 0 = 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t16`.`a` / 0) = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` / 0) = 0) +explain select * from t16 where a + 9223372036854775807 > 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t16`.`a` + 9223372036854775807) > 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` + 9223372036854775807) > 0) +explain select * from t16 where a + 9223372036854775808 > 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t16`.`a` + 9223372036854775808) > 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` + 9223372036854775808) > 0) +explain select * from t16 where a + 18446744073709551615 > 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t16`.`a` + 18446744073709551615) > 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` + 18446744073709551615) > 0) +explain select * from t16 where a + 18446744073709551616 > 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` + 18446744073709551616) > 0) +explain select * from t16 where a > 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`t16`.`a` > 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` > 1) +explain select * from t16 where a >= 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`t16`.`a` >= 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` >= 1) +explain select * from t16 where a < 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`t16`.`a` < 2) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` < 2) +explain select * from t16 where a <= 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`t16`.`a` <= 2) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` <= 2) +explain select * from t16 where a; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 66.67 Using where; Using pushed condition (0 <> `test`.`t16`.`a`) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (0 <> `test`.`t16`.`a`) +explain select * from t16 where a <> 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 66.67 Using where; Using pushed condition (`test`.`t16`.`a` <> 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` <> 0) +explain select * from t16 where a != 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 66.67 Using where; Using pushed condition (`test`.`t16`.`a` <> 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` <> 0) +explain select * from t16 where !a; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`t16`.`a` = 0) +Warnings: +Warning 1287 '!' is deprecated and will be removed in a future release. Please use NOT instead +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` = 0) +explain select * from t16 where NOT a; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`t16`.`a` = 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` = 0) +explain select * from t16 where NOT NOT a; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 66.67 Using where; Using pushed condition (0 <> `test`.`t16`.`a`) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (0 <> `test`.`t16`.`a`) +explain select * from t16 where a <> NULL; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 66.67 Using where; Using pushed condition (`test`.`t16`.`a` <> NULL) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` <> NULL) +explain select * from t16 where a != NULL; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 66.67 Using where; Using pushed condition (`test`.`t16`.`a` <> NULL) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` <> NULL) +explain select * from t16 where a <=> 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`t16`.`a` <=> 2) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` <=> 2) +explain select * from t16 where a <=> NULL; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`t16`.`a` <=> NULL) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` <=> NULL) +explain select * from t16 where a = 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`t16`.`a` = 2) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` = 2) +explain select * from t16 where a = NULL; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`t16`.`a` = NULL) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` = NULL) +explain select * from t16 where a is true; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((0 <> `test`.`t16`.`a`) is true) +explain select * from t16 where a is NOT true; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((0 <> `test`.`t16`.`a`) is not true) +explain select * from t16 where a like 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 33.33 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` like 1) +explain select * from t16 where a not like 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 66.67 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (not((`test`.`t16`.`a` like 1))) +explain select * from t16 where a like NULL; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 33.33 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (`test`.`t16`.`a` like NULL) +explain select * from t16 where a NOT like NULL; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 66.67 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (not((`test`.`t16`.`a` like NULL))) +explain select * from t16 where a + b > 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t16`.`a` + `test`.`t16`.`b`) > 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` + `test`.`t16`.`b`) > 1) +explain select * from t16 where 1 < a; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (1 < `test`.`t16`.`a`) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (1 < `test`.`t16`.`a`) +explain select * from t16 where a - 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition (0 <> (`test`.`t16`.`a` - 1)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (0 <> (`test`.`t16`.`a` - 1)) +explain select * from t16 where a - 2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition (0 <> (`test`.`t16`.`a` - 2)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (0 <> (`test`.`t16`.`a` - 2)) +explain select * from t16 where (a > 1) and (b > 1); +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition ((`test`.`t16`.`a` > 1) and (`test`.`t16`.`b` > 1)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` > 1) and (`test`.`t16`.`b` > 1)) +explain select * from t16 where (a > 1) && (b > 1); +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition ((`test`.`t16`.`a` > 1) and (`test`.`t16`.`b` > 1)) +Warnings: +Warning 1287 '&&' is deprecated and will be removed in a future release. Please use AND instead +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` > 1) and (`test`.`t16`.`b` > 1)) +explain select * from t16 where (a > 1) or (b > 1); +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 55.56 Using where; Using pushed condition ((`test`.`t16`.`a` > 1) or (`test`.`t16`.`b` > 1)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` > 1) or (`test`.`t16`.`b` > 1)) +explain select * from t16 where (a > 1) || (b > 1); +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 55.56 Using where; Using pushed condition ((`test`.`t16`.`a` > 1) or (`test`.`t16`.`b` > 1)) +Warnings: +Warning 1287 '|| as a synonym for OR' is deprecated and will be removed in a future release. Please use OR instead +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` > 1) or (`test`.`t16`.`b` > 1)) +explain select * from t16 where ((a > 1) and (b > 1)) < 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (((`test`.`t16`.`a` > 1) and (`test`.`t16`.`b` > 1)) < 1) +explain select * from t16 where ((a > 1) + (b > 1)) > 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (((`test`.`t16`.`a` > 1) + (`test`.`t16`.`b` > 1)) > 1) +explain select * from t16 where ((a > 1) XOR (b > 1)) < 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where (((`test`.`t16`.`a` > 1) xor (`test`.`t16`.`b` > 1)) < 1) +explain select * from t16 where a = 2 is null; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` = 2) is null) +explain select * from t16 where a = 2 = null; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` = 2) = NULL) +explain select * from t16 where a <=> NULL = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` <=> NULL) = 1) +explain select * from t16 where a + (-2) >= 0; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t16 NULL ALL NULL NULL NULL NULL 3 100.00 Using where; Using pushed condition ((`test`.`t16`.`a` + (-(2))) >= 0) +Warnings: +Note 1003 /* select#1 */ select `test`.`t16`.`a` AS `a`,`test`.`t16`.`b` AS `b` from `test`.`t16` where ((`test`.`t16`.`a` + (-(2))) >= 0) +create table t17 (a int, b int GENERATED ALWAYS AS (a + 1)); +insert into t17(a) values (NULL),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +explain select * from t17 where a > 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t17 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`t17`.`a` > 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t17`.`a` AS `a`,`test`.`t17`.`b` AS `b` from `test`.`t17` where (`test`.`t17`.`a` > 1) +explain select * from t17 where b > 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t17 NULL ALL NULL NULL NULL NULL 3 33.33 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t17`.`a` AS `a`,`test`.`t17`.`b` AS `b` from `test`.`t17` where (`test`.`t17`.`b` > 1) +explain select * from t17 where (a > 1) AND (b > 1); +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t17 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`t17`.`a` > 1) +Warnings: +Note 1003 /* select#1 */ select `test`.`t17`.`a` AS `a`,`test`.`t17`.`b` AS `b` from `test`.`t17` where ((`test`.`t17`.`a` > 1) and (`test`.`t17`.`b` > 1)) +explain select * from t17 where (a > 1) OR (b > 1); +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t17 NULL ALL NULL NULL NULL NULL 3 55.56 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t17`.`a` AS `a`,`test`.`t17`.`b` AS `b` from `test`.`t17` where ((`test`.`t17`.`a` > 1) or (`test`.`t17`.`b` > 1)) +explain select * from t17 where ((a > 1) AND (b > 1)) = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t17 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t17`.`a` AS `a`,`test`.`t17`.`b` AS `b` from `test`.`t17` where (((`test`.`t17`.`a` > 1) and (`test`.`t17`.`b` > 1)) = 1) +explain select * from t17 where ((a > 1) OR (b > 1)) = 1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t17 NULL ALL NULL NULL NULL NULL 3 100.00 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t17`.`a` AS `a`,`test`.`t17`.`b` AS `b` from `test`.`t17` where (((`test`.`t17`.`a` > 1) or (`test`.`t17`.`b` > 1)) = 1) +explain select * from t17 where (a < 5) AND (a > 1) AND (b > 1); +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t17 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition ((`test`.`t17`.`a` < 5) and (`test`.`t17`.`a` > 1)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t17`.`a` AS `a`,`test`.`t17`.`b` AS `b` from `test`.`t17` where ((`test`.`t17`.`a` < 5) and (`test`.`t17`.`a` > 1) and (`test`.`t17`.`b` > 1)) +explain select * from t17 where (a < 5) AND (a > 1) OR (b > 1); +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t17 NULL ALL NULL NULL NULL NULL 3 40.74 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t17`.`a` AS `a`,`test`.`t17`.`b` AS `b` from `test`.`t17` where (((`test`.`t17`.`a` < 5) and (`test`.`t17`.`a` > 1)) or (`test`.`t17`.`b` > 1)) +explain select * from t17 where (a < 5) AND ((a > 1) OR (b > 1)); +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t17 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`t17`.`a` < 5) +Warnings: +Note 1003 /* select#1 */ select `test`.`t17`.`a` AS `a`,`test`.`t17`.`b` AS `b` from `test`.`t17` where ((`test`.`t17`.`a` < 5) and ((`test`.`t17`.`a` > 1) or (`test`.`t17`.`b` > 1))) +explain select * from t17 where (a < 2) OR (a > 8) OR (b > 1); +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t17 NULL ALL NULL NULL NULL NULL 3 70.37 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t17`.`a` AS `a`,`test`.`t17`.`b` AS `b` from `test`.`t17` where ((`test`.`t17`.`a` < 2) or (`test`.`t17`.`a` > 8) or (`test`.`t17`.`b` > 1)) +explain select * from t17 where (a < 2) OR (a > 8) AND (b > 1); +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t17 NULL ALL NULL NULL NULL NULL 3 40.74 Using where; Using pushed condition ((`test`.`t17`.`a` < 2) or (`test`.`t17`.`a` > 8)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t17`.`a` AS `a`,`test`.`t17`.`b` AS `b` from `test`.`t17` where ((`test`.`t17`.`a` < 2) or ((`test`.`t17`.`a` > 8) and (`test`.`t17`.`b` > 1))) +explain select * from t17 where ((a < 2) OR (a > 8)) AND (b > 1); +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t17 NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition ((`test`.`t17`.`a` < 2) or (`test`.`t17`.`a` > 8)) +Warnings: +Note 1003 /* select#1 */ select `test`.`t17`.`a` AS `a`,`test`.`t17`.`b` AS `b` from `test`.`t17` where (((`test`.`t17`.`a` < 2) or (`test`.`t17`.`a` > 8)) and (`test`.`t17`.`b` > 1)) +explain select * from t17 where (a < 2) OR ((a > 8) OR (b > 1)); +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t17 NULL ALL NULL NULL NULL NULL 3 70.37 Using where +Warnings: +Note 1003 /* select#1 */ select `test`.`t17`.`a` AS `a`,`test`.`t17`.`b` AS `b` from `test`.`t17` where ((`test`.`t17`.`a` < 2) or (`test`.`t17`.`a` > 8) or (`test`.`t17`.`b` > 1)) +CREATE TABLE t18(c1 int, c2 int, key(c1,c2)); +INSERT INTO t18 VALUES (94,94),(64,64),(69,69),(97,97); +explain select * from t18; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t18 NULL index NULL c1 10 NULL 3 100.00 Using index +Warnings: +Note 1003 /* select#1 */ select `test`.`t18`.`c1` AS `c1`,`test`.`t18`.`c2` AS `c2` from `test`.`t18` +drop table t1; +drop table t16; +drop table t17; +drop table t18; +create table tb_cache(a int); +insert into tb_cache values(null); +insert into tb_cache values(1); +insert into tb_cache values(0); +prepare stmt1 from 'explain select a from tb_cache where a <=> ?'; +set @arg1 = null; +execute stmt1 using @arg1; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tb_cache NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`tb_cache`.`a` <=> (NULL)) +Warnings: +Note 1003 /* select#1 */ select `test`.`tb_cache`.`a` AS `a` from `test`.`tb_cache` where (`test`.`tb_cache`.`a` <=> (NULL)) +set @arg2 = 1; +execute stmt1 using @arg2; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tb_cache NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`tb_cache`.`a` <=> (1)) +Warnings: +Note 1003 /* select#1 */ select `test`.`tb_cache`.`a` AS `a` from `test`.`tb_cache` where (`test`.`tb_cache`.`a` <=> (1)) +set @arg3 = 'a'; +execute stmt1 using @arg3; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE tb_cache NULL ALL NULL NULL NULL NULL 3 33.33 Using where; Using pushed condition (`test`.`tb_cache`.`a` <=> ('a')) +Warnings: +Warning 1292 Truncated incorrect INTEGER value: 'a' +Warning 1292 Truncated incorrect INTEGER value: 'a' +Note 1003 /* select#1 */ select `test`.`tb_cache`.`a` AS `a` from `test`.`tb_cache` where (`test`.`tb_cache`.`a` <=> ('a')) +drop table tb_cache; diff --git a/mysql-test/suite/ctc/r/ctc_datatype.result b/mysql-test/suite/ctc/r/ctc_datatype.result index 6bfeed5..a9dec02 100644 --- a/mysql-test/suite/ctc/r/ctc_datatype.result +++ b/mysql-test/suite/ctc/r/ctc_datatype.result @@ -370,3 +370,269 @@ IDA 10.5 20.5 drop table t1; +create table t1(int_1 tinyint not null unique, +uint_1 tinyint unsigned not null unique, +int_2 smallint not null unique, +uint_2 smallint unsigned not null unique, +int_3 mediumint not null unique, +uint_3 mediumint unsigned not null unique, +int_4 int not null unique, +uint_4 int unsigned not null unique, +int_8 bigint not null unique, +uint_8 bigint unsigned not null unique); +insert into t1 values (-128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0); +insert into t1 values ( -2, 1, -2, 1, -2, 1, -2, 1, -2, 1); +insert into t1 values ( -1, 2, -1, 2, -1, 2, -1, 2, -1, 2); +insert into t1 values ( 0, 3, 0, 3, 0, 3, 0, 3, 0, 3); +insert into t1 values ( 1, 126, 1, 32767, 65536, 8388608, 1, 2147483648, 1, 9223372036854775808); +insert into t1 values ( 2, 127, 256, 32768, 65537, 8388609, 16777215, 2147483649, 4294967296, 9223372036854775809); +insert into t1 values ( 126, 128, 32766, 65534, 8388606, 16777214, 2147483646, 4294967294, 9223372036854775806, 18446744073709551614); +insert into t1 values ( 127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615); +select * from t1; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-128 0 -32768 0 -8388608 0 -2147483648 0 -9223372036854775808 0 +-2 1 -2 1 -2 1 -2 1 -2 1 +-1 2 -1 2 -1 2 -1 2 -1 2 +0 3 0 3 0 3 0 3 0 3 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +2 127 256 32768 65537 8388609 16777215 2147483649 4294967296 9223372036854775809 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where int_1 < 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-128 0 -32768 0 -8388608 0 -2147483648 0 -9223372036854775808 0 +-2 1 -2 1 -2 1 -2 1 -2 1 +-1 2 -1 2 -1 2 -1 2 -1 2 +select * from t1 where int_1 > 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +2 127 256 32768 65537 8388609 16777215 2147483649 4294967296 9223372036854775809 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where int_1 = 1; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +select * from t1 where int_1 = -1; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-1 2 -1 2 -1 2 -1 2 -1 2 +select * from t1 where int_1 = -128; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-128 0 -32768 0 -8388608 0 -2147483648 0 -9223372036854775808 0 +select * from t1 where int_1 = 127; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where uint_1 < 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +select * from t1 where uint_1 > 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-2 1 -2 1 -2 1 -2 1 -2 1 +-1 2 -1 2 -1 2 -1 2 -1 2 +0 3 0 3 0 3 0 3 0 3 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +2 127 256 32768 65537 8388609 16777215 2147483649 4294967296 9223372036854775809 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where uint_1 = 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-128 0 -32768 0 -8388608 0 -2147483648 0 -9223372036854775808 0 +select * from t1 where uint_1 = 127; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +2 127 256 32768 65537 8388609 16777215 2147483649 4294967296 9223372036854775809 +select * from t1 where uint_1 = 128; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +select * from t1 where uint_1 = 255; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where int_2 < 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-128 0 -32768 0 -8388608 0 -2147483648 0 -9223372036854775808 0 +-2 1 -2 1 -2 1 -2 1 -2 1 +-1 2 -1 2 -1 2 -1 2 -1 2 +select * from t1 where int_2 > 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +2 127 256 32768 65537 8388609 16777215 2147483649 4294967296 9223372036854775809 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where int_2 = 1; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +select * from t1 where int_2 = -1; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-1 2 -1 2 -1 2 -1 2 -1 2 +select * from t1 where int_2 = -32768; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-128 0 -32768 0 -8388608 0 -2147483648 0 -9223372036854775808 0 +select * from t1 where int_2 = 32767; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where uint_2 < 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +select * from t1 where uint_2 > 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-2 1 -2 1 -2 1 -2 1 -2 1 +-1 2 -1 2 -1 2 -1 2 -1 2 +0 3 0 3 0 3 0 3 0 3 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +2 127 256 32768 65537 8388609 16777215 2147483649 4294967296 9223372036854775809 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where uint_2 = 1; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-2 1 -2 1 -2 1 -2 1 -2 1 +select * from t1 where uint_2 = 32768; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +2 127 256 32768 65537 8388609 16777215 2147483649 4294967296 9223372036854775809 +select * from t1 where uint_2 = 65534; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +select * from t1 where uint_2 = 65535; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where int_3 < 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-128 0 -32768 0 -8388608 0 -2147483648 0 -9223372036854775808 0 +-2 1 -2 1 -2 1 -2 1 -2 1 +-1 2 -1 2 -1 2 -1 2 -1 2 +select * from t1 where int_3 > 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +2 127 256 32768 65537 8388609 16777215 2147483649 4294967296 9223372036854775809 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where int_3 = -8388608; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-128 0 -32768 0 -8388608 0 -2147483648 0 -9223372036854775808 0 +select * from t1 where int_3 = -1; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-1 2 -1 2 -1 2 -1 2 -1 2 +select * from t1 where int_3 = 1; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +select * from t1 where int_3 = 8388606; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +select * from t1 where int_3 = 8388607; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where uint_3 < 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +select * from t1 where uint_3 > 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-2 1 -2 1 -2 1 -2 1 -2 1 +-1 2 -1 2 -1 2 -1 2 -1 2 +0 3 0 3 0 3 0 3 0 3 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +2 127 256 32768 65537 8388609 16777215 2147483649 4294967296 9223372036854775809 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where uint_3 = 1; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-2 1 -2 1 -2 1 -2 1 -2 1 +select * from t1 where uint_3 = 8388607; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +select * from t1 where uint_3 = 8388608; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +select * from t1 where uint_3 = 16777214; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +select * from t1 where uint_3 = 16777215; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where int_4 < 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-128 0 -32768 0 -8388608 0 -2147483648 0 -9223372036854775808 0 +-2 1 -2 1 -2 1 -2 1 -2 1 +-1 2 -1 2 -1 2 -1 2 -1 2 +select * from t1 where int_4 > 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +2 127 256 32768 65537 8388609 16777215 2147483649 4294967296 9223372036854775809 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where int_4 = 1; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +select * from t1 where int_4 = -1; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-1 2 -1 2 -1 2 -1 2 -1 2 +select * from t1 where int_4 = -2147483648; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-128 0 -32768 0 -8388608 0 -2147483648 0 -9223372036854775808 0 +select * from t1 where int_4 = 2147483647; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where uint_4 < 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +select * from t1 where uint_4 > 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-2 1 -2 1 -2 1 -2 1 -2 1 +-1 2 -1 2 -1 2 -1 2 -1 2 +0 3 0 3 0 3 0 3 0 3 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +2 127 256 32768 65537 8388609 16777215 2147483649 4294967296 9223372036854775809 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where uint_4 = 1; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-2 1 -2 1 -2 1 -2 1 -2 1 +select * from t1 where uint_4 = 2147483648; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +select * from t1 where uint_4 = 4294967294; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +select * from t1 where uint_4 = 4294967295; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where int_8 < 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-128 0 -32768 0 -8388608 0 -2147483648 0 -9223372036854775808 0 +-2 1 -2 1 -2 1 -2 1 -2 1 +-1 2 -1 2 -1 2 -1 2 -1 2 +select * from t1 where int_8 > 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +2 127 256 32768 65537 8388609 16777215 2147483649 4294967296 9223372036854775809 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where int_8 = 1; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +select * from t1 where int_8 = -1; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-1 2 -1 2 -1 2 -1 2 -1 2 +select * from t1 where int_8 = 4294967296; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +2 127 256 32768 65537 8388609 16777215 2147483649 4294967296 9223372036854775809 +select * from t1 where int_8 = -9223372036854775808; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-128 0 -32768 0 -8388608 0 -2147483648 0 -9223372036854775808 0 +select * from t1 where int_8 = 9223372036854775807; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where uint_8 < 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +select * from t1 where uint_8 > 0; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-2 1 -2 1 -2 1 -2 1 -2 1 +-1 2 -1 2 -1 2 -1 2 -1 2 +0 3 0 3 0 3 0 3 0 3 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +2 127 256 32768 65537 8388609 16777215 2147483649 4294967296 9223372036854775809 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +select * from t1 where uint_8 = 1; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +-2 1 -2 1 -2 1 -2 1 -2 1 +select * from t1 where uint_8 = 9223372036854775808; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +1 126 1 32767 65536 8388608 1 2147483648 1 9223372036854775808 +select * from t1 where uint_8 = 18446744073709551614; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +126 128 32766 65534 8388606 16777214 2147483646 4294967294 9223372036854775806 18446744073709551614 +select * from t1 where uint_8 = 18446744073709551615; +int_1 uint_1 int_2 uint_2 int_3 uint_3 int_4 uint_4 int_8 uint_8 +127 255 32767 65535 8388607 16777215 2147483647 4294967295 9223372036854775807 18446744073709551615 +drop table t1; diff --git a/mysql-test/suite/ctc/r/ctc_datetime_analyze.result b/mysql-test/suite/ctc/r/ctc_datetime_analyze.result index 30ed718..4fd3aea 100644 --- a/mysql-test/suite/ctc/r/ctc_datetime_analyze.result +++ b/mysql-test/suite/ctc/r/ctc_datetime_analyze.result @@ -182,7 +182,7 @@ a 15:15:12 explain select * from tbl_time where a < "15:15:13"; id select_type table partitions type possible_keys key key_len ref rows filtered Extra -1 SIMPLE tbl_time NULL range key_a key_a 4 NULL 2 100.00 Using where; Using pushed condition (`test`.`tbl_time`.`a` < TIME'15:15:13'); Using index +1 SIMPLE tbl_time NULL range key_a key_a 4 NULL 2 100.00 Using where; Using index Warnings: Note 1003 /* select#1 */ select `test`.`tbl_time`.`a` AS `a` from `test`.`tbl_time` where (`test`.`tbl_time`.`a` < TIME'15:15:13') drop table tbl_time; diff --git a/mysql-test/suite/ctc/r/ctc_ddl.result b/mysql-test/suite/ctc/r/ctc_ddl.result index 7c7506f..d97e544 100644 --- a/mysql-test/suite/ctc/r/ctc_ddl.result +++ b/mysql-test/suite/ctc/r/ctc_ddl.result @@ -182,18 +182,6 @@ create table ``(i int); ERROR 42000: Incorrect table name '' create table ` `(i int); ERROR 42000: Incorrect table name ' ' -set debug = '+d, ctc_lock_table_fail'; -set debug = '+d, ctc_lock_table_fail_DDL_LOCKED'; -create table test1(i int); -ERROR HY000: Instance has been locked, disallow this operation -set debug = '-d, ctc_lock_table_fail_DDL_LOCKED'; -set debug = '+d, ctc_lock_table_fail_VERSION_NOT_MATCH'; -create table test1(i int); -ERROR HY000: Version not match. Please make sure cluster on the same version. -set debug = '-d, ctc_lock_table_fail_VERSION_NOT_MATCH'; -set debug = '+d, ctc_lock_table_fail_DISALLOW_OPERATION'; -create table test1(i int); -ERROR HY000: The table or database is being used. Please try again later. set debug = '-d, ctc_lock_table_fail_DISALLOW_OPERATION'; set debug = '-d, ctc_lock_table_fail'; create table test1(i int); diff --git a/mysql-test/suite/ctc/r/ctc_dml_ignore.result b/mysql-test/suite/ctc/r/ctc_dml_ignore.result index 64db8a9..548018e 100644 --- a/mysql-test/suite/ctc/r/ctc_dml_ignore.result +++ b/mysql-test/suite/ctc/r/ctc_dml_ignore.result @@ -432,6 +432,196 @@ drop trigger if exists trg_bug28502_bd; drop trigger if exists trg_bug28502_ad; drop table t1, t1_op_log; drop view v1; +CREATE TABLE `t1` ( +a int, +b int, +KEY `idx_a` (a), +KEY `idx_b` (b) +); +insert into t1(a, b) values(2, 3), (1, 3), (1, 3); +set global ctc_select_prefetch = 0; +select /*+ INDEX_MERGE(t1 idx_a, idx_b) */ count(*) from t1 where a = 1 and b = 3; +count(*) +2 +set global ctc_select_prefetch = 1; +select /*+ INDEX_MERGE(t1 idx_a, idx_b) */ count(*) from t1 where a = 1 and b = 3; +count(*) +2 +create table t2( +id int, +char_col char(20), +enum_col enum('x-small','small','medium','large','x-large'), +primary key (id), +key idx_char_col (char_col), +key idx_enum_col (enum_col)); +insert into t2 values(84, 'apple', 'x-large'), (417, 'apple' , 'x-large'), (439, 'qpple', 'x-large'), (847, 'apple', 'x-large'); +select count(*) from t2 where enum_col = 'x-large' and char_col = 'apple'; +count(*) +3 +set global ctc_select_prefetch = 0; +select /*+ INDEX_MERGE(t2 idx_char_col,idx_enum_col) */ count(*) from t2 where enum_col = 'x-large' and char_col = 'apple'; +count(*) +3 +set global ctc_select_prefetch = 1; +select /*+ INDEX_MERGE(t2 idx_char_col,idx_enum_col) */ count(*) from t2 where enum_col = 'x-large' and char_col = 'apple'; +count(*) +3 +drop table t1; +drop table t2; +CREATE TABLE `t2` ( +id int, +a int, +b int, +KEY `idx_a` (a), +KEY `idx_b` (b) +) +PARTITION BY RANGE (`id`) +(PARTITION p0 VALUES LESS THAN (10) ENGINE = CTC, +PARTITION p1 VALUES LESS THAN (20) ENGINE = CTC, +PARTITION p2 VALUES LESS THAN (30) ENGINE = CTC, +PARTITION p4 VALUES LESS THAN MAXVALUE ENGINE = CTC); +insert into t2 values(30, 2, 3), (20, 1, 3), (10, 1, 3), (null, 1, 3); +explain select /*+ INDEX_MERGE(t2 idx_a, idx_b) */ count(*) from t2 where a = 1 and b = 3; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 p0,p1,p2,p4 index_merge idx_a,idx_b idx_a,idx_b 5,5 NULL 1 100.00 Using intersect(idx_a,idx_b); Using where; Using pushed condition ((`test`.`t2`.`b` = 3) and (`test`.`t2`.`a` = 1)); Using index +Warnings: +Note 1003 /* select#1 */ select /*+ INDEX_MERGE(`t2`@`select#1` `idx_a`, `idx_b`) */ count(0) AS `count(*)` from `test`.`t2` where ((`test`.`t2`.`b` = 3) and (`test`.`t2`.`a` = 1)) +select /*+ INDEX_MERGE(t2 idx_a, idx_b) */ count(*) from t2 where a = 1 and b = 3; +count(*) +3 +explain select count(*) from t2 ignore index(idx_b) where a = 1 and b = 3; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 p0,p1,p2,p4 ref idx_a idx_a 5 const 1 33.33 Using where; Using pushed condition (`test`.`t2`.`b` = 3) +Warnings: +Note 1003 /* select#1 */ select count(0) AS `count(*)` from `test`.`t2` IGNORE INDEX (`idx_b`) where ((`test`.`t2`.`b` = 3) and (`test`.`t2`.`a` = 1)) +select count(*) from t2 ignore index(idx_b) where a = 1 and b = 3; +count(*) +3 +explain select /*+ INDEX_MERGE(t2 idx_a, idx_b) */ count(*) from t2 where a = 1 or b = 3; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 p0,p1,p2,p4 index_merge idx_a,idx_b idx_a,idx_b 5,5 NULL 2 100.00 Using union(idx_a,idx_b); Using where; Using pushed condition ((`test`.`t2`.`a` = 1) or (`test`.`t2`.`b` = 3)) +Warnings: +Note 1003 /* select#1 */ select /*+ INDEX_MERGE(`t2`@`select#1` `idx_a`, `idx_b`) */ count(0) AS `count(*)` from `test`.`t2` where ((`test`.`t2`.`a` = 1) or (`test`.`t2`.`b` = 3)) +select /*+ INDEX_MERGE(t2 idx_a, idx_b) */ count(*) from t2 where a = 1 or b = 3; +count(*) +4 +explain select count(*) from t2 ignore index(idx_b) where a = 1 or b = 3; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t2 p0,p1,p2,p4 ALL idx_a NULL NULL NULL 3 55.56 Using where; Using pushed condition ((`test`.`t2`.`a` = 1) or (`test`.`t2`.`b` = 3)) +Warnings: +Note 1003 /* select#1 */ select count(0) AS `count(*)` from `test`.`t2` IGNORE INDEX (`idx_b`) where ((`test`.`t2`.`a` = 1) or (`test`.`t2`.`b` = 3)) +select count(*) from t2 ignore index(idx_b) where a = 1 or b = 3; +count(*) +4 +drop table t2; +create table t8( +id int, +char_col char(20), +enum_col enum('x-small','small','medium','large','x-large'), +primary key (id), +key idx_char_col (char_col), +key idx_enum_col (enum_col)) +PARTITION BY RANGE (`id`) +(PARTITION p0 VALUES LESS THAN (90) ENGINE = CTC, +PARTITION p1 VALUES LESS THAN (420) ENGINE = CTC, +PARTITION p2 VALUES LESS THAN (510) ENGINE = CTC, +PARTITION p4 VALUES LESS THAN MAXVALUE ENGINE = CTC); +insert into t8 values(84, 'apple', 'x-large'), (417, 'apple' , 'x-large'), (439, 'qpple', 'x-large'), (847, 'apple', 'x-large'); +explain select /*+ INDEX_MERGE(t8 idx_char_col, idx_enum_col) */ count(*) from t8 where enum_col = 'x-large' and char_col = 'apple'; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t8 p0,p1,p2,p4 index_merge idx_char_col,idx_enum_col idx_char_col,idx_enum_col 81,2 NULL 1 100.00 Using intersect(idx_char_col,idx_enum_col); Using where; Using pushed condition (`test`.`t8`.`char_col` = 'apple'); Using index +Warnings: +Note 1003 /* select#1 */ select /*+ INDEX_MERGE(`t8`@`select#1` `idx_char_col`, `idx_enum_col`) */ count(0) AS `count(*)` from `test`.`t8` where ((`test`.`t8`.`char_col` = 'apple') and (`test`.`t8`.`enum_col` = 'x-large')) +select /*+ INDEX_MERGE(t8 idx_char_col, idx_enum_col) */ count(*) from t8 where enum_col = 'x-large' and char_col = 'apple'; +count(*) +3 +explain select count(*) from t8 ignore index(idx_enum_col) where enum_col = 'x-large' and char_col = 'apple'; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t8 p0,p1,p2,p4 ref idx_char_col idx_char_col 81 const 1 33.33 Using where; Using pushed condition (`test`.`t8`.`char_col` = 'apple') +Warnings: +Note 1003 /* select#1 */ select count(0) AS `count(*)` from `test`.`t8` IGNORE INDEX (`idx_enum_col`) where ((`test`.`t8`.`char_col` = 'apple') and (`test`.`t8`.`enum_col` = 'x-large')) +select count(*) from t8 ignore index(idx_enum_col) where enum_col = 'x-large' and char_col = 'apple'; +count(*) +3 +explain select /*+ INDEX_MERGE(t8 idx_char_col, idx_enum_col) */ count(*) from t8 where enum_col = 'x-large' or char_col = 'apple'; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t8 p0,p1,p2,p4 index_merge idx_char_col,idx_enum_col idx_enum_col,idx_char_col 2,81 NULL 2 100.00 Using union(idx_enum_col,idx_char_col); Using where +Warnings: +Note 1003 /* select#1 */ select /*+ INDEX_MERGE(`t8`@`select#1` `idx_char_col`, `idx_enum_col`) */ count(0) AS `count(*)` from `test`.`t8` where ((`test`.`t8`.`enum_col` = 'x-large') or (`test`.`t8`.`char_col` = 'apple')) +select /*+ INDEX_MERGE(t8 idx_char_col, idx_enum_col) */ count(*) from t8 where enum_col = 'x-large' or char_col = 'apple'; +count(*) +4 +explain select count(*) from t8 ignore index(idx_enum_col) where enum_col = 'x-large' or char_col = 'apple'; +id select_type table partitions type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t8 p0,p1,p2,p4 ALL idx_char_col NULL NULL NULL 3 55.56 Using where +Warnings: +Note 1003 /* select#1 */ select count(0) AS `count(*)` from `test`.`t8` IGNORE INDEX (`idx_enum_col`) where ((`test`.`t8`.`enum_col` = 'x-large') or (`test`.`t8`.`char_col` = 'apple')) +select count(*) from t8 ignore index(idx_enum_col) where enum_col = 'x-large' or char_col = 'apple'; +count(*) +4 +drop table t8; +CREATE TABLE `test` ( +`a` int NOT NULL, +`b` int NOT NULL, +KEY `idx_union` (`a`,`b`) +); +insert into test values(2, 2), (3, 3), (4, 4), (5, 5); +analyze table test; +Table Op Msg_type Msg_text +test.test analyze status OK +explain format = json select * from test where a >= 1 and a <= 8 and b = 2; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "cost_info": { + "query_cost": "0.90" + }, + "table": { + "table_name": "test", + "access_type": "index", + "possible_keys": [ + "idx_union" + ], + "key": "idx_union", + "used_key_parts": [ + "a", + "b" + ], + "key_length": "8", + "rows_examined_per_scan": 4, + "rows_produced_per_join": 1, + "filtered": "25.00", + "pushed_condition": "((`test`.`test`.`b` = 2) and (`test`.`test`.`a` >= 1) and (`test`.`test`.`a` <= 8))", + "using_index": true, + "cost_info": { + "read_cost": "0.80", + "eval_cost": "0.10", + "prefix_cost": "0.90", + "data_read_per_join": "16" + }, + "used_columns": [ + "a", + "b" + ], + "attached_condition": "((`test`.`test`.`b` = 2) and (`test`.`test`.`a` >= 1) and (`test`.`test`.`a` <= 8))" + } + } +} +Warnings: +Note 1003 /* select#1 */ select `test`.`test`.`a` AS `a`,`test`.`test`.`b` AS `b` from `test`.`test` where ((`test`.`test`.`b` = 2) and (`test`.`test`.`a` >= 1) and (`test`.`test`.`a` <= 8)) +drop table test; +create table t1(a int(10), key(a)); +Warnings: +Warning 1681 Integer display width is deprecated and will be removed in a future release. +insert into t1 values(1), (2), (1), (1), (2), (1); +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +select count(distinct a) from t1; +count(distinct a) +2 +drop table t1; create database db_trigger; use db_trigger; SET @old_sql_mode := @@sql_mode ; diff --git a/mysql-test/suite/ctc/r/ctc_update_time.result b/mysql-test/suite/ctc/r/ctc_update_time.result index c1f3e69..70f8321 100644 --- a/mysql-test/suite/ctc/r/ctc_update_time.result +++ b/mysql-test/suite/ctc/r/ctc_update_time.result @@ -817,7 +817,7 @@ c2 838:59:59 UPDATE t4 SET c2='-838:59:60' WHERE c1='100:04:04'; Warnings: -Warning 1264 Out of range value for column 'c2' at row 1 +Warning 1264 Out of range value for column 'c2' at row 12 SELECT c2 FROM t4; c2 -838:59:55 @@ -864,7 +864,7 @@ NULL NULL UPDATE t4 SET c2='838:59:60' WHERE c1='100:04:04'; Warnings: -Warning 1264 Out of range value for column 'c2' at row 1 +Warning 1264 Out of range value for column 'c2' at row 12 SELECT c2 FROM t4; c2 -838:59:55 @@ -956,7 +956,7 @@ NULL NULL UPDATE t4 SET c2='11:11:60' WHERE c1='100:04:04'; Warnings: -Warning 1264 Out of range value for column 'c2' at row 1 +Warning 1264 Out of range value for column 'c2' at row 12 SELECT c2 FROM t4; c2 -838:59:55 @@ -1003,7 +1003,7 @@ NULL NULL UPDATE t4 SET c2='11:60:11' WHERE c1='100:04:04'; Warnings: -Warning 1264 Out of range value for column 'c2' at row 1 +Warning 1264 Out of range value for column 'c2' at row 12 SELECT c2 FROM t4; c2 -838:59:55 diff --git a/mysql-test/suite/ctc/t/ctc_cond_pushdown.test b/mysql-test/suite/ctc/t/ctc_cond_pushdown.test index d882afe..f4c93f1 100644 --- a/mysql-test/suite/ctc/t/ctc_cond_pushdown.test +++ b/mysql-test/suite/ctc/t/ctc_cond_pushdown.test @@ -93,14 +93,27 @@ select * from t1 where c1 = 3; select * from t1 where c1 > 3; select * from t1 where c1 != 3; select * from t1 where c2 = 3; +select * from t1 where 255 = c3; +select * from t1 where 255 <=> c3; +select * from t1 where 3 = c1; +select * from t1 where 3 < c1; +select * from t1 where 3 != c1; +select * from t1 where 3 = c2; +select * from t1 where 3 <=> c2; # unsigned select * from t1 where c4 = 255; +select * from t1 where 255 = c4; +select * from t1 where c4 <=> 255; +select * from t1 where 255 <=> c4; # float double select * from t2 where c3 = 11.111; select * from t2 where c4 = 1.1; select * from t2 where c6 = 11.111; +select * from t2 where 11.111 = c3; +select * from t2 where 1.1 = c4; +select * from t2 where 11.111 = c6; # null select * from t1 where null <=> null; @@ -112,7 +125,12 @@ select * from t1 where c1 <=> null; select * from t1 where c1 is null; select * from t1 where c1 is not null; select * from t1 where not c1 <=> null; -select * from t1 where c1 > 3 or c2 = 4 or c3 >=3 or c4 = 5 or (c1 > 1 and c2 < 5 and c3 > 2); +select * from t1 where null = c1; +select * from t1 where null != c1; +select * from t1 where null < c1; +select * from t1 where null > c1; +select * from t1 where null <=> c1; +select * from t1 where not null <=> c1; # decimal select * from t3 where c1 = '22222.22222'; @@ -186,6 +204,13 @@ select * from t1 where not (c1 > 3 and c2 = 4 and c3 >=1); select * from t1 where c1 = 1 xor c2 = 5; select * from t1 where c1 = 1 xor c2 = 1; select * from t1 where c1 > 3 or c2 = 4 or c3 >=3 or c4 = 5 or (c1 > 1 and c2 < 5 and c3 > 2); +select * from t1 where 3 < c1 and 4 = c2 and 1 <= c3; +select * from t1 where 3 < c1 and 8 = c2; +select * from t1 where not c1 > 3; +select * from t1 where not (c1 > 3 and c2 = 4 and c3 >=1); +select * from t1 where c1 = 1 xor c2 = 5; +select * from t1 where c1 = 1 xor c2 = 1; +select * from t1 where 3 < c1 or 4 = c2 or 3 <= c3 or 5 = c4 or (1 < c1 and 5 > c2 and 2 < c3); # index @@ -194,16 +219,26 @@ select c1 from t10 where c1=69; select c1 from t11 where c2=69; select c1 from t11 where c2=69; select c1,c2 from t11 where c2=4; +select c1 from t10 where 69=c2; +select c1 from t10 where 69=c1; +select c1 from t11 where 69=c2; +select c1 from t11 where 69=c1; +select c1,c2 from t11 where 4=c2; # drop column select * from t13 where e_tinyint = 30; +select * from t13 where 30 = e_tinyint; alter table t13 drop column d_deciaml; select * from t13 where e_tinyint = 30; +select * from t13 where 30 = e_tinyint; # binary select hex(c2) from t15 where c2 = 'abcde'; select hex(c2) from t15 where c2 = 0x61626364650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; select hex(c3) from t15 where c3 = 'abcde'; +select hex(c2) from t15 where 'abcde' = c2; +select hex(c2) from t15 where 0x61626364650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 = c2; +select hex(c3) from t15 where 'abcde' = c3; # time select * from t5 where c1 = '01:01:01.01'; @@ -212,24 +247,49 @@ select * from t5 where c1 = '02:02:02'; select * from t5 where c2 = '00:00:00'; select * from t5 where c2 = '1000-01-01 00:00:00'; select * from t5 where c2 = '1999-12-31 23:59:59'; +select * from t5 where '01:01:01.01' = c1; +select * from t5 where '01:01:01.01' > c1; +select * from t5 where '02:02:02' = c1; +select * from t5 where '00:00:00' = c2; +select * from t5 where '1000-01-01 00:00:00' = c2; +select * from t5 where '1999-12-31 23:59:59' = c2; select * from t6 where c1 = '1000-01-01'; select * from t6 where c1 = '1000-01-01 00:00:00'; select * from t6 where c1 > '1000-01-01 00:00:00'; select * from t6 where c2 = '1000-01-01'; select * from t6 where c2 = '1000-01-01 00:00:00'; +select * from t6 where '1000-01-01' = c1; +select * from t6 where '1000-01-01' <=> c1; +select * from t6 where '1000-01-01 00:00:00' = c1; +select * from t6 where '1000-01-01 00:00:00' = c1; +select * from t6 where '1000-01-01' = c2; +select * from t6 where '1000-01-01 00:00:00' = c2; select * from t7 where c1 = '1000-01-01'; select * from t7 where c1 = '1000-01-01 00:00:00'; select * from t7 where c1 > '1000-01-01 00:00:00'; select * from t7 where c2 = '1000-01-01'; select * from t7 where c2 = '1000-01-01 00:00:00'; +select * from t7 where '1000-01-01' = c1; +select * from t7 where '1000-01-01' <=> c1; +select * from t7 where '1000-01-01 00:00:00' = c1; +select * from t7 where '1000-01-01 00:00:00' = c1; +select * from t7 where '1000-01-01' = c2; +select * from t7 where '1000-01-01 00:00:00' = c2; select * from t8 where c1 = '2000-01-01'; select * from t8 where c1 = '2000-01-01 00:00:00'; select * from t8 where c1 > '2000-01-01 00:00:00'; select * from t8 where c2 = '2000-01-01'; select * from t8 where c2 = '2000-01-01 00:00:00'; +select * from t8 where '2000-01-01' = c1; +select * from t8 where '2000-01-01' <=> c1; +select * from t8 where '2000-01-01 00:00:00' = c1; +select * from t8 where '2000-01-01 00:00:00' < c1; +select * from t8 where '2000-01-01 00:00:00' > c1; +select * from t8 where '2000-01-01' = c2; +select * from t8 where '2000-01-01 00:00:00' = c2; select * from t11 where c1 = 4; select * from t11 where c1 = 2004; @@ -238,6 +298,14 @@ select * from t11 where c1 = '2004'; select * from t11 where c1 = 2004.0; #select * from t11 where 'abc' = c1; select * from t11 where '2004' = c1; +select * from t11 where 4 = c1; +select * from t11 where 4 <=> c1; +select * from t11 where 2004 = c1; +select * from t11 where '2004' = c1; +#select * from t11 where 'abc' = c1; +select * from t11 where 2004.0 = c1; +#select * from t11 where c1 = 'abc'; +select * from t11 where c1 = '2004'; # blob: not supported @@ -254,6 +322,7 @@ INSERT INTO tickets(title, priority) VALUES('Scan virus for computer A', 'High') INSERT INTO tickets(title, priority) VALUES('Upgrade Windows OS for all computers', 1); INSERT INTO tickets(title) VALUES('Refresh the computer of Ms. Lily'); SELECT * FROM tickets WHERE priority = 3; +SELECT * FROM tickets WHERE 3 = priority; drop table if exists tickets; # set: not supported @@ -269,8 +338,269 @@ INSERT INTO myset (col) VALUES('a,C,b,d'); select * from myset where col = 'a'; select * from myset where col = 'a,d'; select * from myset where col like 'a,d'; +select * from myset where 'a' = col; +select * from myset where 'a,d' = col; +select * from myset where col like 'a,d'; drop table if exists myset; +drop table if exists t1; + +# ======== Numeric Functions and Operators ======== +## ======== Arithmetic Operators ======== + +CREATE TABLE t1(c1 tinyint, c2 tinyint not null, c3 tinyint signed, c4 tinyint unsigned, c5 int, c6 long, c7 bigint); +INSERT INTO t1 VALUES (1,1,1,1,1,1,1), (2,2,2,2,2,2,2); +INSERT INTO t1 VALUES (null, 5, null, null, null, null, null); +INSERT INTO t1 VALUES (3,3,3,3,3,3,3), (4,4,4,4,4,4,4); +INSERT INTO t1 VALUES (null, 7, null, null, null, null, null); +INSERT INTO t1 VALUES (8,8,127,255,8,8,8); +INSERT INTO t1 VALUES (6,6,6,6,6,6,6), (7,7,7,7,7,7,7); +INSERT INTO t1 VALUES (8,8,8,8,8,8,8), (6,2,3,9,8,4,1); +INSERT INTO t1 VALUES (-1, -2, -4, 8, -16, -32, -20); +select * from t1; + +## mod +select * from t1 where c1 % 2 = 0; +select * from t1 where c2 % 2 = 0; +select * from t1 where c3 % 2 = 0; +select * from t1 where c4 % 2 = 0; +select * from t1 where c5 % 2 = 0; +select * from t1 where c6 % 2 = 0; +select * from t1 where c7 % 2 = 0; +select * from t1 where 2 % c1 = 0; +select * from t1 where 2 % c2 = 0; +select * from t1 where 2 % c3 = 0; +select * from t1 where 2 % c4 = 0; +select * from t1 where 2 % c5 = 0; +select * from t1 where 2 % c6 = 0; +select * from t1 where 2 % c7 = 0; +select * from t1 where 3 % c1 = 0; +select * from t1 where 3 % c2 = 0; +select * from t1 where 3 % c3 = 0; +select * from t1 where 3 % c4 = 0; +select * from t1 where 3 % c5 = 0; +select * from t1 where 3 % c6 = 0; +select * from t1 where 3 % c7 = 0; +select * from t1 where 3 % c1 = c1 % 3; +select * from t1 where 9 % c2 = 3 % c2; +select * from t1 where 3 % c3 = 2 / 3; +select * from t1 where 3 % c4 = 1 * 2; +select * from t1 where 3 % c5 = c2 + c7; +select * from t1 where 3 % c6 = 0; +select * from t1 where 3 % c7 = 0; + +## div +select * from t1 where c1 / 2 = 1; +select * from t1 where c2 / 2 = 1; +select * from t1 where c3 / 2 = 1; +select * from t1 where c4 / 2 = 1; +select * from t1 where c5 / 2 = 1; +select * from t1 where c6 / 2 = 1; +select * from t1 where c7 / 2 = 1; +select * from t1 where c1 / 0 = 1; +select * from t1 where c2 / 0 = 1; +select * from t1 where c3 / 0 = 1; +select * from t1 where c4 / 0 = 1; +select * from t1 where c5 / 0 = 1; +select * from t1 where c6 / 0 = 1; +select * from t1 where c7 / 0 = 1; +select * from t1 where 0 / c1 = 1; +select * from t1 where 0 / c2 = 1; +select * from t1 where 0 / c3 = 1; +select * from t1 where 0 / c4 = 1; +select * from t1 where 0 / c5 = 1; +select * from t1 where 0 / c6 = 1; +select * from t1 where 0 / c7 = 1; +select * from t1 where c1 / c2 = c3 * c7; +select * from t1 where c1 / c2 = c3; +INSERT INTO t1 VALUES (0,0,0,0,0,0,0); +select * from t1 where c1 / 0 = 1; +select * from t1 where c2 / 0 = 1; +select * from t1 where c3 / 0 = 1; +select * from t1 where c4 / 0 = 1; +select * from t1 where c5 / 0 = 1; +select * from t1 where c6 / 0 = 1; +select * from t1 where c7 / 0 = 1; +select * from t1 where 0 / c1 = 1; +select * from t1 where 0 / c2 = 1; +select * from t1 where 0 / c3 = 1; +select * from t1 where 0 / c4 = 1; +select * from t1 where 0 / c5 = 1; +select * from t1 where 0 / c6 = 1; +select * from t1 where 0 / c7 = 1; + +## mul +select * from t1 where c1 * 2 = 1; +select * from t1 where c2 * 2 = 1; +select * from t1 where c3 * 2 = 1; +select * from t1 where c4 * 2 = 1; +select * from t1 where c5 * 2 = 1; +select * from t1 where c6 * 2 = 1; +select * from t1 where c7 * 2 = 1; +select * from t1 where 2 * c1 = 1; +select * from t1 where 2 * c2 = 1; +select * from t1 where 2 * c3 = 1; +select * from t1 where 2 * c4 = 1; +select * from t1 where 2 * c5 = 1; +select * from t1 where 2 * c6 = 1; +select * from t1 where 2 * c7 = 1; +select * from t1 where 2 * c1 = c1 * 2; +select * from t1 where 2 * c2 = c2 * 2; +select * from t1 where 2 * c3 = c3 * 2; +select * from t1 where 2 * c4 = c4 * 2; +select * from t1 where 2 * c5 = c5 * 2; +select * from t1 where 2 * c6 = c6 * 2; +select * from t1 where 2 * c7 = c7 * 2; +select * from t1 where 2 * c1 = c1 * 2 * 1; +select * from t1 where 2 * c2 = c2 * 2 / 1; +select * from t1 where 2 * c3 = c3 * 2 / 2 * 2; +select * from t1 where 2 * c4 = c4 * 2 / 3 * 3; +select * from t1 where 2 * c5 = c5 * 2 / 3 * 2; +select * from t1 where 2 * c6 = c6 * 2 / 4 * 2; +select * from t1 where 2 * c7 = c7 * 2; +select * from t1 where c1 / 2 = c2 / 2; +select * from t1 where c1 / 3 = c2 * 3; +select * from t1 where c1 * c2 = c3 * c6; +select * from t1 where c1 * c2 = c3 * c6 * c7; + +## add +select * from t1 where c1 + 2 = 1; +select * from t1 where c2 + 2 = 1; +select * from t1 where c3 + 2 = 1; +select * from t1 where c4 + 2 = 1; +select * from t1 where c5 + 2 = 1; +select * from t1 where c6 + 2 = 1; +select * from t1 where c7 + 2 = 1; +select c1 + 2 + 2 from t1; +select * from t1 where c1 + 2 + 2 = 4; +select c2 + 2 * 2 from t1; +select * from t1 where c2 + 2 * 2 = 8; +select c3 + 2 / 3 from t1; +select * from t1 where c3 + 2 / 3 = 1; +select c4 + 2 / 4 from t1; +select * from t1 where c4 + 2 / 4 = 1; +select c5 + 4 / 2 from t1; +select * from t1 where c5 + 4 / 2 = 1; +select c5 + 4 / 2 from t1; +select * from t1 where c6 + 2 * c7 = 6; +select * from t1 where 2 + c7 = -1; + +## sub +select * from t1 where c1 - 2 = 1; +select * from t1 where c2 - 2 = 1; +select * from t1 where c3 - 2 = 1; +select * from t1 where c4 - 2 = 1; +select * from t1 where c5 - 2 = 1; +select * from t1 where c6 - 2 = 1; +select * from t1 where c7 - 2 = 1; +--error 1690 +select * from t1 where 4 - c4 = 4 - c4; +select * from t1 where c4 - c1 = c4 - c1; +select * from t1 where c3 - 2 = 1; + +create table t16 (a int, b int unsigned); +insert into t16 values (1,2),(2,1),(NULL,NULL),(1,NULL),(NULL,1); +select * from t16; + +# change sign +select * from t16 where -a < 0; + +# case of invalid +select * from t16 where a - '2' >= 0; +select * from t16 where a % 0 = 0; +select * from t16 where a / 0 = 0; + +## ======== Out of range ======== +## signed int out of range +--error ER_DATA_OUT_OF_RANGE +select * from t16 where a + 9223372036854775807 > 0; + +## unsigned int +select * from t16 where a + 9223372036854775808 > 0; + +## unsigned int out of range +--error ER_DATA_OUT_OF_RANGE +select * from t16 where a + 18446744073709551615 > 0; + +## decimal +select * from t16 where a + 18446744073709551616 > 0; + +## ======== Comparison Functions and Operators ======== + +select * from t16 where a > 1; +select * from t16 where a >= 1; +select * from t16 where a < 2; +select * from t16 where a <= 2; + +## Not equal operator +select * from t16 where a; +select * from t16 where a <> 0; +select * from t16 where a != 0; +select * from t16 where !a; +select * from t16 where NOT a; +select * from t16 where NOT NOT a; +select * from t16 where a <> NULL; +select * from t16 where a != NULL; + +## NULL-SAFE EQUAL +select * from t16 where a <=> 2; +select * from t16 where a <=> NULL; + +## Equal operator +select * from t16 where a = 2; +select * from t16 where a = NULL; + +## unsupported IS / IS NOT +select * from t16 where a is true; +select * from t16 where a is NOT true; + + +## unsupported LIKE / NOT +select * from t16 where a like 1; +select * from t16 where a not like 1; +select * from t16 where a like NULL; +select * from t16 where a NOT like NULL; + +select * from t16 where a + b > 1; +select * from t16 where 1 < a; +select * from t16 where a - 1; +select * from t16 where a - 2; + +# ======== Logical Operators ======== +select * from t16 where (a > 1) and (b > 1); +select * from t16 where (a > 1) && (b > 1); +select * from t16 where (a > 1) or (b > 1); +select * from t16 where (a > 1) || (b > 1); +select * from t16 where ((a > 1) and (b > 1)) < 1; +select * from t16 where ((a > 1) + (b > 1)) > 1; +select * from t16 where ((a > 1) XOR (b > 1)) < 1; + +select * from t16 where a = 2 is null; +select * from t16 where a = 2 = null; +select * from t16 where a <=> NULL = 1; + +select * from t16 where a + (-2) >= 0; + +create table t17 (a int, b int GENERATED ALWAYS AS (a + 1)); +insert into t17(a) values (NULL),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +select * from t17 where a > 1; +select * from t17 where b > 1; +select * from t17 where (a > 1) AND (b > 1); +select * from t17 where (a > 1) OR (b > 1); +select * from t17 where ((a > 1) AND (b > 1)) = 1; +select * from t17 where ((a > 1) OR (b > 1)) = 1; +select * from t17 where (a < 5) AND (a > 1) AND (b > 1); +select * from t17 where (a < 5) AND (a > 1) OR (b > 1); +select * from t17 where (a < 5) AND ((a > 1) OR (b > 1)); +select * from t17 where (a < 2) OR (a > 8) OR (b > 1); +select * from t17 where (a < 2) OR (a > 8) AND (b > 1); +select * from t17 where ((a < 2) OR (a > 8)) AND (b > 1); +select * from t17 where (a < 2) OR ((a > 8) OR (b > 1)); + +CREATE TABLE t18(c1 int, c2 int, key(c1,c2)); +INSERT INTO t18 VALUES (94,94),(64,64),(69,69),(97,97); +select * from t18; + drop table t1; drop table t2; drop table t3; @@ -285,4 +615,28 @@ drop table t11; drop table t12; drop table t13; drop table t14; -drop table t15; \ No newline at end of file +drop table t15; +drop table t16; +drop table t17; +drop table t18; + +# ======== cache item ============ +# cache item +## cache int + +create table tb_cache(a int); +insert into tb_cache values(null); +insert into tb_cache values(1); +insert into tb_cache values(0); + +prepare stmt1 from 'select a from tb_cache where a <=> ?'; + +set @arg1 = null; +execute stmt1 using @arg1; + +set @arg2 = 1; +execute stmt1 using @arg2; + +set @arg3 = 'a'; +execute stmt1 using @arg3; +drop table tb_cache; diff --git a/mysql-test/suite/ctc/t/ctc_cond_pushdown_explain.test b/mysql-test/suite/ctc/t/ctc_cond_pushdown_explain.test index e283388..429a448 100644 --- a/mysql-test/suite/ctc/t/ctc_cond_pushdown_explain.test +++ b/mysql-test/suite/ctc/t/ctc_cond_pushdown_explain.test @@ -137,4 +137,282 @@ select * from t7 where c4 != -39; explain select * from t7 where c4 != -39; --enable_warnings -drop table t1, t2, t3, t4, t5, t6, t7; \ No newline at end of file +drop table t1, t2, t3, t4, t5, t6, t7; + +# ======== Numeric Functions and Operators ======== +## ======== Arithmetic Operators ======== + +CREATE TABLE t1(c1 tinyint, c2 tinyint not null, c3 tinyint signed, c4 tinyint unsigned, c5 int, c6 long, c7 bigint); +INSERT INTO t1 VALUES (1,1,1,1,1,1,1), (2,2,2,2,2,2,2); +INSERT INTO t1 VALUES (null, 5, null, null, null, null, null); +INSERT INTO t1 VALUES (3,3,3,3,3,3,3), (4,4,4,4,4,4,4); +INSERT INTO t1 VALUES (null, 7, null, null, null, null, null); +INSERT INTO t1 VALUES (8,8,127,255,8,8,8); +INSERT INTO t1 VALUES (6,6,6,6,6,6,6), (7,7,7,7,7,7,7); +INSERT INTO t1 VALUES (8,8,8,8,8,8,8), (6,2,3,9,8,4,1); +INSERT INTO t1 VALUES (-1, -2, -4, 8, -16, -32, -20); + +## mod +explain select * from t1 where c1 % 2 = 0; +explain select * from t1 where c2 % 2 = 0; +explain select * from t1 where c3 % 2 = 0; +explain select * from t1 where c4 % 2 = 0; +explain select * from t1 where c5 % 2 = 0; +explain select * from t1 where c6 % 2 = 0; +explain select * from t1 where c7 % 2 = 0; +explain select * from t1 where 2 % c1 = 0; +explain select * from t1 where 2 % c2 = 0; +explain select * from t1 where 2 % c3 = 0; +explain select * from t1 where 2 % c4 = 0; +explain select * from t1 where 2 % c5 = 0; +explain select * from t1 where 2 % c6 = 0; +explain select * from t1 where 2 % c7 = 0; +explain select * from t1 where 3 % c1 = 0; +explain select * from t1 where 3 % c2 = 0; +explain select * from t1 where 3 % c3 = 0; +explain select * from t1 where 3 % c4 = 0; +explain select * from t1 where 3 % c5 = 0; +explain select * from t1 where 3 % c6 = 0; +explain select * from t1 where 3 % c7 = 0; +explain select * from t1 where 3 % c1 = c1 % 3; +explain select * from t1 where 9 % c2 = 3 % c2; +explain select * from t1 where 3 % c3 = 2 / 3; +explain select * from t1 where 3 % c4 = 1 * 2; +explain select * from t1 where 3 % c5 = c2 + c7; +explain select * from t1 where 3 % c6 = 0; +explain select * from t1 where 3 % c7 = 0; + +## div +explain select * from t1 where c1 / 2 = 1; +explain select * from t1 where c2 / 2 = 1; +explain select * from t1 where c3 / 2 = 1; +explain select * from t1 where c4 / 2 = 1; +explain select * from t1 where c5 / 2 = 1; +explain select * from t1 where c6 / 2 = 1; +explain select * from t1 where c7 / 2 = 1; +explain select * from t1 where c1 / 0 = 1; +explain select * from t1 where c2 / 0 = 1; +explain select * from t1 where c3 / 0 = 1; +explain select * from t1 where c4 / 0 = 1; +explain select * from t1 where c5 / 0 = 1; +explain select * from t1 where c6 / 0 = 1; +explain select * from t1 where c7 / 0 = 1; +explain select * from t1 where 0 / c1 = 1; +explain select * from t1 where 0 / c2 = 1; +explain select * from t1 where 0 / c3 = 1; +explain select * from t1 where 0 / c4 = 1; +explain select * from t1 where 0 / c5 = 1; +explain select * from t1 where 0 / c6 = 1; +explain select * from t1 where 0 / c7 = 1; +explain select * from t1 where c1 / c2 = c3 * c7; +explain select * from t1 where c1 / c2 = c3; +INSERT INTO t1 VALUES (0,0,0,0,0,0,0); +explain select * from t1 where c1 / 0 = 1; +explain select * from t1 where c2 / 0 = 1; +explain select * from t1 where c3 / 0 = 1; +explain select * from t1 where c4 / 0 = 1; +explain select * from t1 where c5 / 0 = 1; +explain select * from t1 where c6 / 0 = 1; +explain select * from t1 where c7 / 0 = 1; +explain select * from t1 where 0 / c1 = 1; +explain select * from t1 where 0 / c2 = 1; +explain select * from t1 where 0 / c3 = 1; +explain select * from t1 where 0 / c4 = 1; +explain select * from t1 where 0 / c5 = 1; +explain select * from t1 where 0 / c6 = 1; +explain select * from t1 where 0 / c7 = 1; + +## mul +explain select * from t1 where c1 * 2 = 1; +explain select * from t1 where c2 * 2 = 1; +explain select * from t1 where c3 * 2 = 1; +explain select * from t1 where c4 * 2 = 1; +explain select * from t1 where c5 * 2 = 1; +explain select * from t1 where c6 * 2 = 1; +explain select * from t1 where c7 * 2 = 1; +explain select * from t1 where 2 * c1 = 1; +explain select * from t1 where 2 * c2 = 1; +explain select * from t1 where 2 * c3 = 1; +explain select * from t1 where 2 * c4 = 1; +explain select * from t1 where 2 * c5 = 1; +explain select * from t1 where 2 * c6 = 1; +explain select * from t1 where 2 * c7 = 1; +explain select * from t1 where 2 * c1 = c1 * 2; +explain select * from t1 where 2 * c2 = c2 * 2; +explain select * from t1 where 2 * c3 = c3 * 2; +explain select * from t1 where 2 * c4 = c4 * 2; +explain select * from t1 where 2 * c5 = c5 * 2; +explain select * from t1 where 2 * c6 = c6 * 2; +explain select * from t1 where 2 * c7 = c7 * 2; +explain select * from t1 where 2 * c1 = c1 * 2 * 1; +explain select * from t1 where 2 * c2 = c2 * 2 / 1; +explain select * from t1 where 2 * c3 = c3 * 2 / 2 * 2; +explain select * from t1 where 2 * c4 = c4 * 2 / 3 * 3; +explain select * from t1 where 2 * c5 = c5 * 2 / 3 * 2; +explain select * from t1 where 2 * c6 = c6 * 2 / 4 * 2; +explain select * from t1 where 2 * c7 = c7 * 2; +explain select * from t1 where c1 / 2 = c2 / 2; +explain select * from t1 where c1 / 3 = c2 * 3; +explain select * from t1 where c1 * c2 = c3 * c6; +explain select * from t1 where c1 * c2 = c3 * c6 * c7; + +## add +explain select * from t1 where c1 + 2 = 1; +explain select * from t1 where c2 + 2 = 1; +explain select * from t1 where c3 + 2 = 1; +explain select * from t1 where c4 + 2 = 1; +explain select * from t1 where c5 + 2 = 1; +explain select * from t1 where c6 + 2 = 1; +explain select * from t1 where c7 + 2 = 1; +explain select c1 + 2 + 2 from t1; +explain select * from t1 where c1 + 2 + 2 = 4; +explain select c2 + 2 * 2 from t1; +explain select * from t1 where c2 + 2 * 2 = 8; +explain select c3 + 2 / 3 from t1; +explain select * from t1 where c3 + 2 / 3 = 1; +explain select c4 + 2 / 4 from t1; +explain select * from t1 where c4 + 2 / 4 = 1; +explain select c5 + 4 / 2 from t1; +explain select * from t1 where c5 + 4 / 2 = 1; +explain select c5 + 4 / 2 from t1; +explain select * from t1 where c6 + 2 * c7 = 6; +explain select * from t1 where 2 + c7 = -1; + +## sub +explain select * from t1 where c1 - 2 = 1; +explain select * from t1 where c2 - 2 = 1; +explain select * from t1 where c3 - 2 = 1; +explain select * from t1 where c4 - 2 = 1; +explain select * from t1 where c5 - 2 = 1; +explain select * from t1 where c6 - 2 = 1; +explain select * from t1 where c7 - 2 = 1; +explain select * from t1 where 4 - c4 = 4 - c4; +explain select * from t1 where c4 - c1 = c4 - c1; +explain select * from t1 where c3 - 2 = 1; + +create table t16 (a int, b int unsigned); +insert into t16 values (1,2),(2,1),(NULL,NULL),(1,NULL),(NULL,1); +explain select * from t16; + +# change sign +explain select * from t16 where -a < 0; + +# case of invalid +explain select * from t16 where a - '2' >= 0; +explain select * from t16 where a % 0 = 0; +explain select * from t16 where a / 0 = 0; + +## ======== Out of range ======== +## signed int out of range +explain select * from t16 where a + 9223372036854775807 > 0; + +## unsigned int +explain select * from t16 where a + 9223372036854775808 > 0; + +## unsigned int out of range +explain select * from t16 where a + 18446744073709551615 > 0; + +## decimal +explain select * from t16 where a + 18446744073709551616 > 0; + +## ======== Comparison Functions and Operators ======== + +explain select * from t16 where a > 1; +explain select * from t16 where a >= 1; +explain select * from t16 where a < 2; +explain select * from t16 where a <= 2; + +## Not equal operator +explain select * from t16 where a; +explain select * from t16 where a <> 0; +explain select * from t16 where a != 0; +explain select * from t16 where !a; +explain select * from t16 where NOT a; +explain select * from t16 where NOT NOT a; +explain select * from t16 where a <> NULL; +explain select * from t16 where a != NULL; + +## NULL-SAFE EQUAL +explain select * from t16 where a <=> 2; +explain select * from t16 where a <=> NULL; + +## Equal operator +explain select * from t16 where a = 2; +explain select * from t16 where a = NULL; + +## unsupported IS / IS NOT +explain select * from t16 where a is true; +explain select * from t16 where a is NOT true; + + +## unsupported LIKE / NOT +explain select * from t16 where a like 1; +explain select * from t16 where a not like 1; +explain select * from t16 where a like NULL; +explain select * from t16 where a NOT like NULL; + +explain select * from t16 where a + b > 1; +explain select * from t16 where 1 < a; +explain select * from t16 where a - 1; +explain select * from t16 where a - 2; + +# ======== Logical Operators ======== +explain select * from t16 where (a > 1) and (b > 1); +explain select * from t16 where (a > 1) && (b > 1); +explain select * from t16 where (a > 1) or (b > 1); +explain select * from t16 where (a > 1) || (b > 1); +explain select * from t16 where ((a > 1) and (b > 1)) < 1; +explain select * from t16 where ((a > 1) + (b > 1)) > 1; +explain select * from t16 where ((a > 1) XOR (b > 1)) < 1; + +explain select * from t16 where a = 2 is null; +explain select * from t16 where a = 2 = null; +explain select * from t16 where a <=> NULL = 1; + +explain select * from t16 where a + (-2) >= 0; + +create table t17 (a int, b int GENERATED ALWAYS AS (a + 1)); +insert into t17(a) values (NULL),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10); +explain select * from t17 where a > 1; +explain select * from t17 where b > 1; +explain select * from t17 where (a > 1) AND (b > 1); +explain select * from t17 where (a > 1) OR (b > 1); +explain select * from t17 where ((a > 1) AND (b > 1)) = 1; +explain select * from t17 where ((a > 1) OR (b > 1)) = 1; +explain select * from t17 where (a < 5) AND (a > 1) AND (b > 1); +explain select * from t17 where (a < 5) AND (a > 1) OR (b > 1); +explain select * from t17 where (a < 5) AND ((a > 1) OR (b > 1)); +explain select * from t17 where (a < 2) OR (a > 8) OR (b > 1); +explain select * from t17 where (a < 2) OR (a > 8) AND (b > 1); +explain select * from t17 where ((a < 2) OR (a > 8)) AND (b > 1); +explain select * from t17 where (a < 2) OR ((a > 8) OR (b > 1)); + +CREATE TABLE t18(c1 int, c2 int, key(c1,c2)); +INSERT INTO t18 VALUES (94,94),(64,64),(69,69),(97,97); +explain select * from t18; + +drop table t1; +drop table t16; +drop table t17; +drop table t18; + +# ======== cache item ============ +# cache item +## cache int + +create table tb_cache(a int); +insert into tb_cache values(null); +insert into tb_cache values(1); +insert into tb_cache values(0); + +prepare stmt1 from 'explain select a from tb_cache where a <=> ?'; + +set @arg1 = null; +execute stmt1 using @arg1; + +set @arg2 = 1; +execute stmt1 using @arg2; + +set @arg3 = 'a'; +execute stmt1 using @arg3; +drop table tb_cache; diff --git a/mysql-test/suite/ctc/t/ctc_datatype.test b/mysql-test/suite/ctc/t/ctc_datatype.test index f9db9d5..8a4a321 100644 --- a/mysql-test/suite/ctc/t/ctc_datatype.test +++ b/mysql-test/suite/ctc/t/ctc_datatype.test @@ -278,3 +278,100 @@ CREATE INDEX floatIndexTest ON t1 (IDA); select * from t1 where IDA < 20.0; select * from t1 where IDA > 10.0; drop table t1; + + +create table t1(int_1 tinyint not null unique, + uint_1 tinyint unsigned not null unique, + int_2 smallint not null unique, + uint_2 smallint unsigned not null unique, + int_3 mediumint not null unique, + uint_3 mediumint unsigned not null unique, + int_4 int not null unique, + uint_4 int unsigned not null unique, + int_8 bigint not null unique, + uint_8 bigint unsigned not null unique); + +insert into t1 values (-128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0); +insert into t1 values ( -2, 1, -2, 1, -2, 1, -2, 1, -2, 1); +insert into t1 values ( -1, 2, -1, 2, -1, 2, -1, 2, -1, 2); +insert into t1 values ( 0, 3, 0, 3, 0, 3, 0, 3, 0, 3); +insert into t1 values ( 1, 126, 1, 32767, 65536, 8388608, 1, 2147483648, 1, 9223372036854775808); +insert into t1 values ( 2, 127, 256, 32768, 65537, 8388609, 16777215, 2147483649, 4294967296, 9223372036854775809); +insert into t1 values ( 126, 128, 32766, 65534, 8388606, 16777214, 2147483646, 4294967294, 9223372036854775806, 18446744073709551614); +insert into t1 values ( 127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615); + +select * from t1; +select * from t1 where int_1 < 0; +select * from t1 where int_1 > 0; +select * from t1 where int_1 = 1; +select * from t1 where int_1 = -1; +select * from t1 where int_1 = -128; +select * from t1 where int_1 = 127; + +select * from t1 where uint_1 < 0; +select * from t1 where uint_1 > 0; +select * from t1 where uint_1 = 0; +select * from t1 where uint_1 = 127; +select * from t1 where uint_1 = 128; +select * from t1 where uint_1 = 255; + +select * from t1 where int_2 < 0; +select * from t1 where int_2 > 0; +select * from t1 where int_2 = 1; +select * from t1 where int_2 = -1; +select * from t1 where int_2 = -32768; +select * from t1 where int_2 = 32767; + +select * from t1 where uint_2 < 0; +select * from t1 where uint_2 > 0; +select * from t1 where uint_2 = 1; +select * from t1 where uint_2 = 32768; +select * from t1 where uint_2 = 65534; +select * from t1 where uint_2 = 65535; + +select * from t1 where int_3 < 0; +select * from t1 where int_3 > 0; +select * from t1 where int_3 = -8388608; +select * from t1 where int_3 = -1; +select * from t1 where int_3 = 1; +select * from t1 where int_3 = 8388606; +select * from t1 where int_3 = 8388607; + +select * from t1 where uint_3 < 0; +select * from t1 where uint_3 > 0; +select * from t1 where uint_3 = 1; +select * from t1 where uint_3 = 8388607; +select * from t1 where uint_3 = 8388608; +select * from t1 where uint_3 = 16777214; +select * from t1 where uint_3 = 16777215; + +select * from t1 where int_4 < 0; +select * from t1 where int_4 > 0; +select * from t1 where int_4 = 1; +select * from t1 where int_4 = -1; +select * from t1 where int_4 = -2147483648; +select * from t1 where int_4 = 2147483647; + +select * from t1 where uint_4 < 0; +select * from t1 where uint_4 > 0; +select * from t1 where uint_4 = 1; +select * from t1 where uint_4 = 2147483648; +select * from t1 where uint_4 = 4294967294; +select * from t1 where uint_4 = 4294967295; + +select * from t1 where int_8 < 0; +select * from t1 where int_8 > 0; +select * from t1 where int_8 = 1; +select * from t1 where int_8 = -1; +select * from t1 where int_8 = 4294967296; +select * from t1 where int_8 = -9223372036854775808; +select * from t1 where int_8 = 9223372036854775807; + +select * from t1 where uint_8 < 0; +select * from t1 where uint_8 > 0; +select * from t1 where uint_8 = 1; +select * from t1 where uint_8 = 9223372036854775808; +select * from t1 where uint_8 = 18446744073709551614; +select * from t1 where uint_8 = 18446744073709551615; + +drop table t1; \ No newline at end of file diff --git a/mysql-test/suite/ctc/t/ctc_ddl.test b/mysql-test/suite/ctc/t/ctc_ddl.test index 28239c2..512fff0 100644 --- a/mysql-test/suite/ctc/t/ctc_ddl.test +++ b/mysql-test/suite/ctc/t/ctc_ddl.test @@ -119,18 +119,6 @@ create table `@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#$` create table ``(i int); --error ER_WRONG_TABLE_NAME create table ` `(i int); -set debug = '+d, ctc_lock_table_fail'; -set debug = '+d, ctc_lock_table_fail_DDL_LOCKED'; ---error ER_DISALLOWED_OPERATION -create table test1(i int); -set debug = '-d, ctc_lock_table_fail_DDL_LOCKED'; -set debug = '+d, ctc_lock_table_fail_VERSION_NOT_MATCH'; ---error ER_DISALLOWED_OPERATION -create table test1(i int); -set debug = '-d, ctc_lock_table_fail_VERSION_NOT_MATCH'; -set debug = '+d, ctc_lock_table_fail_DISALLOW_OPERATION'; ---error ER_DISALLOWED_OPERATION -create table test1(i int); set debug = '-d, ctc_lock_table_fail_DISALLOW_OPERATION'; set debug = '-d, ctc_lock_table_fail'; create table test1(i int); diff --git a/mysql-test/suite/ctc/t/ctc_dml_ignore.test b/mysql-test/suite/ctc/t/ctc_dml_ignore.test index 3da3a32..fb464b6 100644 --- a/mysql-test/suite/ctc/t/ctc_dml_ignore.test +++ b/mysql-test/suite/ctc/t/ctc_dml_ignore.test @@ -192,6 +192,97 @@ drop trigger if exists trg_bug28502_ad; drop table t1, t1_op_log; drop view v1; +CREATE TABLE `t1` ( + a int, + b int, + KEY `idx_a` (a), + KEY `idx_b` (b) +); +insert into t1(a, b) values(2, 3), (1, 3), (1, 3); +set global ctc_select_prefetch = 0; +select /*+ INDEX_MERGE(t1 idx_a, idx_b) */ count(*) from t1 where a = 1 and b = 3; +set global ctc_select_prefetch = 1; +select /*+ INDEX_MERGE(t1 idx_a, idx_b) */ count(*) from t1 where a = 1 and b = 3; + +create table t2( + id int, + char_col char(20), + enum_col enum('x-small','small','medium','large','x-large'), + primary key (id), + key idx_char_col (char_col), + key idx_enum_col (enum_col)); +insert into t2 values(84, 'apple', 'x-large'), (417, 'apple' , 'x-large'), (439, 'qpple', 'x-large'), (847, 'apple', 'x-large'); +select count(*) from t2 where enum_col = 'x-large' and char_col = 'apple'; +set global ctc_select_prefetch = 0; +select /*+ INDEX_MERGE(t2 idx_char_col,idx_enum_col) */ count(*) from t2 where enum_col = 'x-large' and char_col = 'apple'; +set global ctc_select_prefetch = 1; +select /*+ INDEX_MERGE(t2 idx_char_col,idx_enum_col) */ count(*) from t2 where enum_col = 'x-large' and char_col = 'apple'; + +drop table t1; +drop table t2; + +CREATE TABLE `t2` ( + id int, + a int, + b int, + KEY `idx_a` (a), + KEY `idx_b` (b) +) +PARTITION BY RANGE (`id`) +(PARTITION p0 VALUES LESS THAN (10) ENGINE = CTC, +PARTITION p1 VALUES LESS THAN (20) ENGINE = CTC, +PARTITION p2 VALUES LESS THAN (30) ENGINE = CTC, +PARTITION p4 VALUES LESS THAN MAXVALUE ENGINE = CTC); +insert into t2 values(30, 2, 3), (20, 1, 3), (10, 1, 3), (null, 1, 3); +explain select /*+ INDEX_MERGE(t2 idx_a, idx_b) */ count(*) from t2 where a = 1 and b = 3; +select /*+ INDEX_MERGE(t2 idx_a, idx_b) */ count(*) from t2 where a = 1 and b = 3; +explain select count(*) from t2 ignore index(idx_b) where a = 1 and b = 3; +select count(*) from t2 ignore index(idx_b) where a = 1 and b = 3; +explain select /*+ INDEX_MERGE(t2 idx_a, idx_b) */ count(*) from t2 where a = 1 or b = 3; +select /*+ INDEX_MERGE(t2 idx_a, idx_b) */ count(*) from t2 where a = 1 or b = 3; +explain select count(*) from t2 ignore index(idx_b) where a = 1 or b = 3; +select count(*) from t2 ignore index(idx_b) where a = 1 or b = 3; +drop table t2; + +create table t8( + id int, + char_col char(20), + enum_col enum('x-small','small','medium','large','x-large'), + primary key (id), + key idx_char_col (char_col), + key idx_enum_col (enum_col)) +PARTITION BY RANGE (`id`) +(PARTITION p0 VALUES LESS THAN (90) ENGINE = CTC, +PARTITION p1 VALUES LESS THAN (420) ENGINE = CTC, +PARTITION p2 VALUES LESS THAN (510) ENGINE = CTC, +PARTITION p4 VALUES LESS THAN MAXVALUE ENGINE = CTC); +insert into t8 values(84, 'apple', 'x-large'), (417, 'apple' , 'x-large'), (439, 'qpple', 'x-large'), (847, 'apple', 'x-large'); +explain select /*+ INDEX_MERGE(t8 idx_char_col, idx_enum_col) */ count(*) from t8 where enum_col = 'x-large' and char_col = 'apple'; +select /*+ INDEX_MERGE(t8 idx_char_col, idx_enum_col) */ count(*) from t8 where enum_col = 'x-large' and char_col = 'apple'; +explain select count(*) from t8 ignore index(idx_enum_col) where enum_col = 'x-large' and char_col = 'apple'; +select count(*) from t8 ignore index(idx_enum_col) where enum_col = 'x-large' and char_col = 'apple'; +explain select /*+ INDEX_MERGE(t8 idx_char_col, idx_enum_col) */ count(*) from t8 where enum_col = 'x-large' or char_col = 'apple'; +select /*+ INDEX_MERGE(t8 idx_char_col, idx_enum_col) */ count(*) from t8 where enum_col = 'x-large' or char_col = 'apple'; +explain select count(*) from t8 ignore index(idx_enum_col) where enum_col = 'x-large' or char_col = 'apple'; +select count(*) from t8 ignore index(idx_enum_col) where enum_col = 'x-large' or char_col = 'apple'; +drop table t8; + +CREATE TABLE `test` ( + `a` int NOT NULL, + `b` int NOT NULL, + KEY `idx_union` (`a`,`b`) +); +insert into test values(2, 2), (3, 3), (4, 4), (5, 5); +analyze table test; +explain format = json select * from test where a >= 1 and a <= 8 and b = 2; +drop table test; + +create table t1(a int(10), key(a)); +insert into t1 values(1), (2), (1), (1), (2), (1); +analyze table t1; +select count(distinct a) from t1; +drop table t1; + create database db_trigger; use db_trigger; SET @old_sql_mode := @@sql_mode ; diff --git a/storage/ctc/CMakeLists.txt b/storage/ctc/CMakeLists.txt index b4e60e1..6703afc 100644 --- a/storage/ctc/CMakeLists.txt +++ b/storage/ctc/CMakeLists.txt @@ -15,7 +15,8 @@ SET(CTC_PLUGIN_DYNAMIC "ha_ctc") SET(CTC_SOURCES ctc_log.h ha_ctc.cc ha_ctc.h ha_ctcpart.h ha_ctcpart.cc ha_ctc_ddl.cc ha_ctc_ddl.h ctc_ddl_util.cc ctc_ddl_util.h datatype_cnvrtr.cc datatype_cnvrtr.h ctc_error.cc ctc_error.h decimal_convert.cc decimal_convert.h ctc_cbo.cc ctc_cbo.h datatype_cnvrt_4_index_search.cc datatype_cnvrt_4_index_search.h ctc_ddl_rewriter_plugin.cc - ctc_meta_data.cc ctc_meta_data.h ctc_stats.h ctc_stats.cc ctc_srv.h ctc_util.h ctc_util.cc protobuf/tc_db.pb-c.c protobuf/tc_db.pb-c.h) + ctc_meta_data.cc ctc_meta_data.h ctc_stats.h ctc_stats.cc ctc_srv.h ctc_util.h ctc_util.cc protobuf/tc_db.pb-c.c protobuf/tc_db.pb-c.h + ha_ctc_pq.cc ha_ctc_pq.h) option(WITH_CANTIAN OFF) IF (WITH_CANTIAN) add_definitions(-DWITH_CANTIAN) @@ -25,6 +26,14 @@ ELSE () list(APPEND CTC_SOURCES ctc_srv_mq_stub.cc ctc_srv_mq_module.cc ctc_srv_mq_module.h srv_mq_msg.h message_queue/dsw_shm.h message_queue/dsw_list.h message_queue/dsw_message.h message_queue/dsw_typedef.h) ENDIF () +option(FEATURE_FOR_EVERSQL OFF) +IF (FEATURE_FOR_EVERSQL) + add_definitions(-DFEATURE_FOR_EVERSQL=1) + message(STATUS "ADD FEATURE FOR EVERSQL") +ELSE () + add_definitions(-DFEATURE_FOR_EVERSQL=0) + message(STATUS "Dummy Feature For EverSQL, Mock class added") +ENDIF () ADD_DEFINITIONS(-DMYSQL_SERVER) ADD_DEFINITIONS(-DMYSQL_DYNAMIC_PLUGIN) STRING_APPEND(CMAKE_CXX_FLAGS " -Wno-implicit-fallthrough") @@ -59,14 +68,14 @@ IF (WITH_CANTIAN) ${CTC_SOURCES} STORAGE_ENGINE MANDATORY - LINK_LIBRARIES libzecommon.so libzeclient.so libzeprotocol.so libprotobuf-c.a pcre2-8 ctc_proxy cantian + LINK_LIBRARIES libzecommon.so libzeclient.so libzeprotocol.so libprotobuf-c.a pcre2-8 ctc_proxy libcantian.so ) ELSEIF (NOT WITHOUT_CTC_STORAGE_ENGINE) MYSQL_ADD_PLUGIN(ctc ${CTC_SOURCES} STORAGE_ENGINE MODULE_ONLY - LINK_LIBRARIES libzecommon.so libzeclient.so libzeprotocol.so libprotobuf-c.a pcre2-8 ctc_proxy cantian + LINK_LIBRARIES libzecommon.so libzeclient.so libzeprotocol.so libprotobuf-c.a pcre2-8 ctc_proxy libcantian.so ) ENDIF () ELSE () @@ -75,14 +84,14 @@ ELSE () ${CTC_SOURCES} STORAGE_ENGINE DEFAULT - LINK_LIBRARIES message_queue libprotobuf-c.a libsecurec.so ctc_proxy + LINK_LIBRARIES libmessage_queue.so libprotobuf-c.a libsecurec.so ctc_proxy ) ELSEIF (NOT WITHOUT_CTC_STORAGE_ENGINE) MYSQL_ADD_PLUGIN(ctc ${CTC_SOURCES} STORAGE_ENGINE MODULE_ONLY - LINK_LIBRARIES message_queue libprotobuf-c.a libsecurec.so ctc_proxy + LINK_LIBRARIES libmessage_queue.so libprotobuf-c.a libsecurec.so ctc_proxy ) ENDIF () ENDIF () diff --git a/storage/ctc/ctc_cbo.cc b/storage/ctc/ctc_cbo.cc index d9ec830..5f45fa3 100644 --- a/storage/ctc/ctc_cbo.cc +++ b/storage/ctc/ctc_cbo.cc @@ -578,7 +578,7 @@ static double calc_hist_between_density(ctc_cbo_stats_table_t *cbo_stats, } double calc_density_by_cond(ctc_cbo_stats_table_t *cbo_stats, KEY_PART_INFO cur_index_part, ctc_range_key *key, - uint32_t key_offset, uint32_t col_id, const CHARSET_INFO *cs) + uint32_t key_offset, uint32_t col_id, const CHARSET_INFO *cs, bool *continue_calc) { double density = DEFAULT_RANGE_DENSITY; ctc_key *min_key = key->min_key; @@ -601,11 +601,17 @@ double calc_density_by_cond(ctc_cbo_stats_table_t *cbo_stats, KEY_PART_INFO cur_ } extract_boundary_value(min_key, &cur_index_part, &min_key_val, low_val, key_offset); extract_boundary_value(max_key, &cur_index_part, &max_key_val, high_val, key_offset); + + en_ctc_compare_type comapare_value = compare(&max_key_val, &min_key_val, cur_index_part.field, cs); + if (comapare_value != EQUAL) { + // 联合索引上下界不同时,当前列为范围查询,下一列开始不符合联合索引的最左匹配原则,无需继续计算 + *continue_calc = false; + } if (compare(&max_key_val, low_val, cur_index_part.field, cs) == LESS || compare(&min_key_val, high_val, cur_index_part.field, cs) == GREAT) { return 0; } - en_ctc_compare_type comapare_value = compare(&max_key_val, &min_key_val, cur_index_part.field, cs); + if (comapare_value == EQUAL && min_key->cmp_type == CMP_TYPE_CLOSE_INTERNAL && max_key->cmp_type == CMP_TYPE_CLOSE_INTERNAL) { return calc_hist_equal_density(cbo_stats, &max_key_val, col_id, cur_index_part.field, cs); @@ -633,7 +639,8 @@ void calc_accumulate_gcol_num(uint num_fields, Field** field, uint32_t *acc_gcol } double calculate_column_selectivity(ctc_cbo_stats_table_t *cbo_stats, ctc_range_key* key, KEY_PART_INFO *cur_index_part, - uint32_t ctc_col_id, uint32_t key_offset, bool is_nullable, const CHARSET_INFO *cs) + uint32_t ctc_col_id, uint32_t key_offset, bool is_nullable, const CHARSET_INFO *cs, + bool *continue_calc) { double col_selectivity = 0.0; @@ -648,7 +655,8 @@ double calculate_column_selectivity(ctc_cbo_stats_table_t *cbo_stats, ctc_range_ /*when the col of min_key and max_key both have null-val --> select * from table where col is null*/ col_selectivity = calc_equal_null_density(cbo_stats, ctc_col_id); } else { - col_selectivity = calc_density_by_cond(cbo_stats, *cur_index_part, key, key_offset, ctc_col_id, cs); + col_selectivity = calc_density_by_cond(cbo_stats, *cur_index_part, key, key_offset, + ctc_col_id, cs, continue_calc); } return col_selectivity; @@ -704,7 +712,8 @@ double calc_density_one_table(uint16_t idx_id, ctc_range_key *key, * For all columns in used index, * density = 1.0 / (column[0]->num_distinct * ... * column[n]->num_distinct) */ - for (uint32_t idx_col_num = 0; idx_col_num < cur_index.actual_key_parts; idx_col_num++) { + bool continue_calc = true; + for (uint32_t idx_col_num = 0; idx_col_num < cur_index.actual_key_parts && continue_calc; idx_col_num++) { double col_selectivity = 0.0; if ((valid_map & ((uint64_t)1 << idx_col_num)) == 0) { break; @@ -723,7 +732,8 @@ double calc_density_one_table(uint16_t idx_id, ctc_range_key *key, set_key_boundary_types(key, idx_col_num, min_key_cmp_type, max_key_cmp_type); col_selectivity = calculate_column_selectivity(cbo_stats, key, &cur_index_part, ctc_col_id, - key_offset, null_offset, table.field[mysql_col_id]->charset()); + key_offset, null_offset, table.field[mysql_col_id]->charset(), + &continue_calc); col_selectivity = eval_density_result(col_selectivity); key_offset += (varchar_offset + null_offset + cur_index_part.field->key_length()); diff --git a/storage/ctc/ctc_cbo.h b/storage/ctc/ctc_cbo.h index 1cccb4d..3bc9688 100644 --- a/storage/ctc/ctc_cbo.h +++ b/storage/ctc/ctc_cbo.h @@ -75,10 +75,11 @@ double calc_density_one_table(uint16_t idx_id, ctc_range_key *key, void calc_accumulate_gcol_num(uint num_fields, Field** field, uint32_t *acc_gcol_num); void ctc_index_stats_update(TABLE *table, ctc_cbo_stats_t *cbo_stats); double calc_density_by_cond(ctc_cbo_stats_table_t *cbo_stats, KEY_PART_INFO cur_index_part, ctc_range_key *key, - uint32_t key_offset, uint32_t col_id, const CHARSET_INFO *cs); + uint32_t key_offset, uint32_t col_id, const CHARSET_INFO *cs, bool *continue_calc); void set_key_boundary_types(ctc_range_key *key, uint32_t id, ctc_cmp_type_t min_key_cmp_type, ctc_cmp_type_t max_key_cmp_type); double calculate_column_selectivity(ctc_cbo_stats_table_t *cbo_stats, ctc_range_key* key, KEY_PART_INFO *cur_index_part, - uint32_t ctc_col_id, uint32_t key_offset, bool is_nullable, const CHARSET_INFO *cs); + uint32_t ctc_col_id, uint32_t key_offset, bool is_nullable, const CHARSET_INFO *cs, + bool *continue_calc); void extract_boundary_value(ctc_key *rKey, KEY_PART_INFO *cur_index_part, cache_variant_t *ret_val, cache_variant_t * value, uint32_t key_offset); bool handle_null_and_single_boundary(ctc_key *rKey, Field *field, cache_variant_t *ret_val, diff --git a/storage/ctc/ctc_ddl_rewriter_plugin.cc b/storage/ctc/ctc_ddl_rewriter_plugin.cc index e211c5a..15ddec1 100644 --- a/storage/ctc/ctc_ddl_rewriter_plugin.cc +++ b/storage/ctc/ctc_ddl_rewriter_plugin.cc @@ -208,10 +208,20 @@ int unsupport_tx_isolation_level(set_var *setvar, bool &need_forward MY_ATTRIBUT return -1; } +int ctc_check_sample_size(set_var *setvar MY_ATTRIBUTE((unused)), + bool &need_forward, + string user_val_str MY_ATTRIBUTE((unused))) { + need_forward = false; + push_warning_printf(current_thd, Sql_condition::SL_WARNING, ER_DISALLOWED_OPERATION, + "CTC: This parameter will not be broadcast to other nodes."); + return 0; +} + static std::unordered_map set_variable_rules_map = { {"default_storage_engine", check_default_engine}, {"max_connections", check_session_pool_volume}, - {"transaction_isolation", unsupport_tx_isolation_level} + {"transaction_isolation", unsupport_tx_isolation_level}, + {"ctc_sample_size", ctc_check_sample_size} }; static int ctc_get_user_var_string(MYSQL_THD thd, Item_func_get_user_var *itemFunc, string &user_val_str) { @@ -463,7 +473,7 @@ static int ctc_set_var_meta(MYSQL_THD thd, list variables_info, ct for (auto it = variables_info.begin(); it != variables_info.end(); ++it) { auto var_info = *it; strncpy(set_opt_info_begin->var_name, var_info.var_name, SMALL_RECORD_SIZE - 1); - strncpy(set_opt_info_begin->var_value, var_info.var_value, CTC_MAX_VAR_VALUE_LEN - 1); + strncpy(set_opt_info_begin->var_value, var_info.var_value, MAX_DDL_SQL_LEN - 1); set_opt_info_begin->options |= CTC_NOT_NEED_CANTIAN_EXECUTE; set_opt_info_begin->options |= (thd->lex->contains_plaintext_password ? CTC_CURRENT_SQL_CONTAIN_PLAINTEXT_PASSWORD : 0); @@ -581,7 +591,7 @@ static void ctc_set_var_info(set_var_info *var_info, const char *base_name, stri strncpy(var_info->base_name, base_name, SMALL_RECORD_SIZE - 1); } strncpy(var_info->var_name, name.c_str(), SMALL_RECORD_SIZE - 1); - strncpy(var_info->var_value, value.c_str(), CTC_MAX_VAR_VALUE_LEN - 1); + strncpy(var_info->var_value, value.c_str(), MAX_DDL_SQL_LEN - 1); var_info->options = options; var_info->var_is_int = var_is_int; } @@ -662,12 +672,7 @@ static int check_system_var(set_var_base *var, string &sql_str, MYSQL_THD thd, ret |= ctc_check_set_opt_rule(setvar, name_str, val_str, need_forward); } } - if (val_str.c_str() == nullptr) { - my_printf_error(ER_DISALLOWED_OPERATION, "Set the variable '%s' failed: value is invalid", - MYF(0), name_str.c_str()); - return -1; - } - if (strlen(val_str.c_str()) > CTC_MAX_VAR_VALUE_LEN) { + if (strlen(val_str.c_str()) > MAX_DDL_SQL_LEN) { my_printf_error(ER_DISALLOWED_OPERATION, "Set the variable '%s' failed: value is too long", MYF(0), name_str.c_str()); return -1; @@ -731,11 +736,15 @@ static int ctc_check_set_opt(string &sql_str, MYSQL_THD thd, bool &need_forward) ctc_log_debug("set option %s, need_forward: %d", sql_str.c_str(), need_forward); } if (!variables_info.empty()) { + if (variables_info.size() > CTC_MAX_SET_VAR_NUM) { + my_printf_error(ER_DISALLOWED_OPERATION, "Only %d variables can be set at a time", MYF(0), CTC_MAX_SET_VAR_NUM); + return -1; + } ctc_set_opt_request set_opt_request; ret = ctc_set_var_meta(thd, variables_info, &set_opt_request); if (ret != 0 && set_opt_request.err_code != 0) { string err_msg = set_opt_request.err_msg; - my_printf_error(set_opt_request.err_code, "execute set opt failed, error_message:%s", MYF(0), err_msg.c_str()); + my_printf_error(set_opt_request.err_code, "%s", MYF(0), err_msg.c_str()); return ret; } } diff --git a/storage/ctc/ctc_meta_data.cc b/storage/ctc/ctc_meta_data.cc index 8de0c1f..6fdbfd9 100644 --- a/storage/ctc/ctc_meta_data.cc +++ b/storage/ctc/ctc_meta_data.cc @@ -552,7 +552,10 @@ static typename std::enable_if::typ return 0; } -int ctc_invalidate_mysql_dd_cache(ctc_handler_t *tch, ctc_invalidate_broadcast_request *broadcast_req, int *err_code) { +int ctc_invalidate_mysql_dd_cache_req(ctc_handler_t *tch, + ctc_invalidate_broadcast_request *broadcast_req, + int *err_code) +{ return (int)ctc_invalidate_mysql_dd_cache_impl(tch, broadcast_req, err_code); } @@ -583,6 +586,7 @@ static void ctc_init_mdl_request(ctc_lock_table_info *lock_info, MDL_request *md dd::Trigger::create_mdl_key(schema_name, name, &mdl_key); MDL_REQUEST_INIT_BY_KEY(mdl_request, &mdl_key, MDL_EXCLUSIVE, MDL_EXPLICIT); break; + case MDL_key::GLOBAL: case MDL_key::BACKUP_LOCK: MDL_REQUEST_INIT(mdl_request, ctc_mdl_namespace, lock_info->db_name, lock_info->table_name, MDL_SHARED, MDL_EXPLICIT); @@ -618,10 +622,8 @@ int ctc_mdl_lock_thd(ctc_handler_t *tch, ctc_lock_table_info *lock_info, int *er MDL_request ctc_mdl_request; ctc_init_mdl_request(lock_info, &ctc_mdl_request); - if (thd->mdl_context.acquire_lock(&ctc_mdl_request, 10)) { + if (thd->mdl_context.acquire_lock(&ctc_mdl_request, 1)) { *err_code = ER_LOCK_WAIT_TIMEOUT; - ctc_log_error("[CTC_MDL_LOCK]:Failed to get mdl lock of namespace:%d , db_name:%s and table_name:%s", - lock_info->mdl_namespace, lock_info->db_name, lock_info->table_name); return true; } @@ -775,7 +777,6 @@ int close_ctc_mdl_thd(uint32_t thd_id, uint32_t mysql_inst_id) { static void ctc_get_set_var_item(THD* new_thd, sys_var* sysvar, Item** res MY_ATTRIBUTE((unused)), const char* var_value, bool is_null_value, bool var_is_int) { - string val_str = string(var_value, strlen(var_value)); switch (sysvar->show_type()) { case SHOW_INT: case SHOW_LONG: @@ -794,7 +795,7 @@ static void ctc_get_set_var_item(THD* new_thd, sys_var* sysvar, Item** res MY_AT break; case SHOW_BOOL: case SHOW_MY_BOOL: - if(val_str == "1" || val_str == "0") { + if(strcmp(var_value, "1") == 0 || strcmp(var_value, "0") == 0) { *res = new (new_thd->mem_root) Item_int(var_value, (uint)strlen(var_value)); } else { @@ -966,7 +967,6 @@ int ctc_set_sys_var(ctc_set_opt_request *broadcast_req) { lex_end(new_thd->lex); new_thd->release_resources(); delete new_thd; - my_thread_end(); return ret; @@ -989,10 +989,8 @@ int ctc_ddl_execute_lock_tables_by_req(ctc_handler_t *tch, ctc_lock_table_info * MDL_request ctc_mdl_request; ctc_init_mdl_request(lock_info, &ctc_mdl_request, MDL_key::TABLE); - if (thd->mdl_context.acquire_lock(&ctc_mdl_request, 10)) { + if (thd->mdl_context.acquire_lock(&ctc_mdl_request, 1)) { *err_code = ER_LOCK_WAIT_TIMEOUT; - ctc_log_error("[CTC_MDL_LOCK]:Get mdl lock fail. namespace:%d, db_name:%s, table_name:%s", - lock_info->mdl_namespace, lock_info->db_name, lock_info->table_name); return true; } diff --git a/storage/ctc/ctc_meta_data.h b/storage/ctc/ctc_meta_data.h index 5ba8b19..56ebae7 100644 --- a/storage/ctc/ctc_meta_data.h +++ b/storage/ctc/ctc_meta_data.h @@ -31,6 +31,9 @@ void ctc_mdl_unlock_thd(ctc_handler_t *tch, ctc_lock_table_info *lock_info); int ctc_set_sys_var(ctc_set_opt_request *broadcast_req); int ctc_ddl_execute_lock_tables_by_req(ctc_handler_t *tch, ctc_lock_table_info *lock_info, int *err_code); void ctc_mdl_unlock_tables_thd(ctc_handler_t *tch); +int ctc_invalidate_mysql_dd_cache_req(ctc_handler_t *tch, + ctc_invalidate_broadcast_request *broadcast_req, + int *err_code); #pragma GCC visibility pop diff --git a/storage/ctc/ctc_mysql_proxy.cc b/storage/ctc/ctc_mysql_proxy.cc index 8ba50be..a7546fc 100644 --- a/storage/ctc/ctc_mysql_proxy.cc +++ b/storage/ctc/ctc_mysql_proxy.cc @@ -52,6 +52,8 @@ using namespace std; +__attribute__((visibility("default"))) mutex m_ctc_cluster_role_mutex; +__attribute__((visibility("default"))) int32_t ctc_cluster_role = (int32_t)dis_cluster_role::DEFAULT; struct ctc_mysql_conn_info { MYSQL* conn; set> table_lock_info; // 连接上已存在的表锁 (db, table) @@ -455,6 +457,34 @@ __attribute__((visibility("default"))) int ctc_ddl_execute_set_opt(uint32_t thd_ return ret; } +__attribute__((visibility("default"))) void ctc_set_mysql_read_only() { + ctc_log_system("[Disaster Recovecy] starting or initializing"); + super_read_only = true; + read_only = true; + opt_readonly = true; + ctc_log_system("[Disaster Recovery] set super_read_only = true."); +} + +__attribute__((visibility("default"))) void ctc_reset_mysql_read_only() { + ctc_log_system("[Disaster Recovecy] starting or initializing"); + super_read_only = false; + read_only = false; + opt_readonly = false; + ctc_log_system("[Disaster Recovery] set super_read_only = false."); +} + +__attribute__((visibility("default"))) int ctc_set_cluster_role_by_cantian(bool is_slave) { + lock_guard lock(m_ctc_mysql_proxy_mutex); + if (is_slave) { + ctc_cluster_role = (int32_t)dis_cluster_role::STANDBY; + ctc_set_mysql_read_only(); + } else { + ctc_cluster_role = (int32_t)dis_cluster_role::PRIMARY; + ctc_reset_mysql_read_only(); + } + return 0; +} + static int ctc_ddl_get_lock(MYSQL *curr_conn, const uint64_t &conn_map_key, const char *lock_name, int *err_code) { uchar digest[MD5_HASH_SIZE]; compute_md5_hash(pointer_cast(digest), lock_name, strlen(lock_name)); @@ -521,8 +551,11 @@ int32_t ctc_check_table_exist(MYSQL *curr_conn_proxy, const char *db_name, const return res; } -__attribute__((visibility("default"))) int ctc_ddl_execute_lock_tables(ctc_handler_t *tch, char *db_name, ctc_lock_table_info *lock_info, int *err_code) { - +__attribute__((visibility("default"))) int ctc_ddl_execute_lock_tables(ctc_handler_t *tch, + char *db_name, + ctc_lock_table_info *lock_info, + int *err_code) +{ if (IS_METADATA_NORMALIZATION()) { if (lock_info->sql_type == SQLCOM_LOCK_TABLES) { if (ctc_ddl_execute_lock_tables_by_req(tch, lock_info, err_code)) { @@ -616,7 +649,7 @@ __attribute__((visibility("default"))) int ctc_ddl_execute_lock_tables(ctc_handl } __attribute__((visibility("default"))) int ctc_ddl_execute_unlock_tables(ctc_handler_t *tch, uint32_t mysql_inst_id, ctc_lock_table_info *lock_info) - { +{ if (IS_METADATA_NORMALIZATION()) { UNUSED_PARAM(mysql_inst_id); if (lock_info->sql_type == SQLCOM_UNLOCK_TABLES) { @@ -717,4 +750,11 @@ __attribute__((visibility("default"))) int close_mysql_connection(uint32_t thd_i close_mysql_conn_by_key(agent_conn_map_key); } return 0; +} + +__attribute__((visibility("default"))) int ctc_invalidate_mysql_dd_cache(ctc_handler_t *tch, + ctc_invalidate_broadcast_request *broadcast_req, + int *err_code) +{ + return ctc_invalidate_mysql_dd_cache_req(tch, broadcast_req, err_code); } \ No newline at end of file diff --git a/storage/ctc/ctc_srv.h b/storage/ctc/ctc_srv.h index 352ef37..87e72ba 100644 --- a/storage/ctc/ctc_srv.h +++ b/storage/ctc/ctc_srv.h @@ -20,7 +20,7 @@ #include #include - +#include "sql/tztime.h" #ifdef __cplusplus extern "C" { #endif @@ -38,6 +38,8 @@ extern "C" { #define ERROR_MESSAGE_LEN 512 #define MAX_DDL_SQL_LEN_CONTEXT (63488) // 62kb, 预留2kb #define MAX_DDL_SQL_LEN (MAX_DDL_SQL_LEN_CONTEXT + 30) // ddl sql语句的长度 不能超过64kb, 超过了会报错 +#define MAX_DML_SQL_LEN_CONTEXT (8192) +#define MAX_DML_SQL_LEN (MAX_DML_SQL_LEN_CONTEXT + 30) // dml sql语句的长度 不能超过8000, 超过了会截断 #define DD_BROADCAST_RECORD_LENGTH (3072) #define LOCK_TABLE_SQL_FMT_LEN 20 #define MAX_LOCK_TABLE_NAME (MAX_DDL_SQL_LEN - LOCK_TABLE_SQL_FMT_LEN) @@ -57,6 +59,7 @@ extern "C" { #define MAX_BULK_INSERT_PART_ROWS 128 #define SESSION_CURSOR_NUM (8192 * 2) #define MAX_MESSAGE_SIZE 4194304 // 共享内存最大可申请空间大小 +#define CT_MAX_PARAL_QUERY 256 // for broadcast_req.options #define CTC_SET_VARIABLE_PERSIST (0x1 << 8) @@ -72,8 +75,6 @@ extern "C" { #define CTC_AUTOINC_NEW_STYLE_LOCKING 1 #define CTC_AUTOINC_NO_LOCKING 2 -#define CTC_MAX_VAR_VALUE_LEN 1024 - typedef int64_t date_t; typedef struct { @@ -146,8 +147,6 @@ typedef struct { typedef struct { uint32_t estimate_rows; ctc_cbo_stats_column_t *columns; - uint32_t blocks; - uint32_t avg_row_len; } ctc_cbo_stats_table_t; /* @@ -164,7 +163,6 @@ typedef struct { uint32_t num_str_cols; bool *col_type; ctc_cbo_stats_table_t *ctc_cbo_stats_table; - uint32_t page_size; } ctc_cbo_stats_t; #pragma pack() @@ -210,7 +208,7 @@ typedef struct { typedef struct { char base_name[SMALL_RECORD_SIZE]; char var_name[SMALL_RECORD_SIZE]; - char var_value[CTC_MAX_VAR_VALUE_LEN]; + char var_value[MAX_DDL_SQL_LEN]; uint32_t options; bool var_is_int; } set_opt_info_t; @@ -303,6 +301,8 @@ enum CTC_FUNC_TYPE { CTC_FUNC_TYPE_UPDATE_JOB, CTC_FUNC_TYPE_UPDATE_ROW, CTC_FUNC_TYPE_DELETE_ROW, + CTC_FUNC_TYPE_UPDATE_SAMPLE_SIZE, + CTC_FUNC_TYPE_GET_SAMPLE_SIZE, CTC_FUNC_TYPE_RND_INIT, CTC_FUNC_TYPE_RND_END, CTC_FUNC_TYPE_RND_NEXT, @@ -310,6 +310,8 @@ enum CTC_FUNC_TYPE { CTC_FUNC_TYPE_SCAN_RECORDS, CTC_FUNC_TYPE_TRX_COMMIT, CTC_FUNC_TYPE_TRX_ROLLBACK, + CTC_FUNC_TYPE_STATISTIC_BEGIN, + CTC_FUNC_TYPE_STATISTIC_COMMIT, CTC_FUNC_TYPE_TRX_BEGIN, CTC_FUNC_TYPE_LOCK_TABLE, CTC_FUNC_TYPE_UNLOCK_TABLE, @@ -357,6 +359,10 @@ enum CTC_FUNC_TYPE { CTC_FUNC_KILL_CONNECTION, CTC_FUNC_TYPE_INVALIDATE_OBJECT, CTC_FUNC_TYPE_RECORD_SQL, + CTC_FUNC_TYPE_GET_PARAL_SCHEDULE, + CTC_FUNC_TYPE_GET_INDEX_PARAL_SCHEDULE, + CTC_FUNC_TYPE_PQ_INDEX_READ, + CTC_FUNC_TYPE_PQ_SET_CURSOR_RANGE, /* for instance registration, should be the last but before duplex */ CTC_FUNC_TYPE_REGISTER_INSTANCE, CTC_FUNC_QUERY_SHM_FILE_NUM, @@ -468,7 +474,6 @@ typedef struct ctc_db_infos { } ctc_db_infos_t; typedef enum en_ctc_func_type_t { - CTC_UNKNOWN_FUNC, CTC_EQ_FUNC, CTC_EQUAL_FUNC, CTC_NE_FUNC, @@ -479,18 +484,37 @@ typedef enum en_ctc_func_type_t { CTC_LIKE_FUNC, CTC_ISNULL_FUNC, CTC_ISNOTNULL_FUNC, - CTC_NOT_FUNC, CTC_COND_AND_FUNC, CTC_COND_OR_FUNC, - CTC_XOR_FUNC + CTC_XOR_FUNC, + CTC_MOD_FUNC, + CTC_PLUS_FUNC, + CTC_MINUS_FUNC, + CTC_MUL_FUNC, + CTC_DIV_FUNC, + CTC_DATE_FUNC, + CTC_UNKNOWN_FUNC } ctc_func_type_t; +typedef enum en_ctc_cond_type_t { + CTC_FIELD_EXPR, + CTC_CONST_EXPR, + CTC_NULL_EXPR, + CTC_LIKE_EXPR, + CTC_CMP_EXPR, + CTC_LOGIC_EXPR, + CTC_ARITHMATIC_EXPR, + CTC_DATE_EXPR, + CTC_UNKNOWN_EXPR +} ctc_cond_type_t; + typedef struct en_ctc_cond_field_t { uint16_t field_no; enum_ctc_ddl_field_types field_type; uint16_t field_size; void *field_value; bool null_value; + bool is_unsigned; uint32_t collate_id; bool col_updated; bool index_only_invalid_col; // col in cond but not in index while select with index_only @@ -499,6 +523,7 @@ typedef struct en_ctc_cond_field_t { struct en_ctc_cond_list_t; typedef struct en_ctc_cond_t { + ctc_cond_type_t cond_type; ctc_func_type_t func_type; ctc_cond_field field_info; struct en_ctc_cond_list_t *cond_list; @@ -511,6 +536,49 @@ typedef struct en_ctc_cond_list_t { uint16_t elements; } ctc_cond_list; +// parallel to knl_scan_key_t +typedef struct en_ctc_scan_key { + uint8_t flags[16]; + uint16_t offsets[16]; + char *buf; +} ctc_scan_key_t; + +typedef union en_ctc_page_id { + uint32_t vmid; + struct { + uint32_t page; + uint16_t file; + uint16_t aligned; + }; +} ctc_page_id_t; + +// guaranteed to be parallel to knl_scan_range_t +typedef struct en_ctc_scan_range { + union { + struct { + char l_buf[4096]; // 4096 as CT_KEY_BUF_SIZE + char r_buf[4096]; + char org_buf[4096]; + ctc_scan_key_t l_key; + ctc_scan_key_t r_key; + ctc_scan_key_t org_key; + uint32_t is_equal; + }; + + struct { + ctc_page_id_t l_page; + ctc_page_id_t r_page; + }; + }; +} ctc_scan_range_t; + +// splitting at most to CT_MAX_PARAL_QUERY part, single index scan range should not have more part than this +// by-page scan shall also be wrapped in this as response type +typedef struct en_ctc_index_paral_range { + uint32_t workers; + ctc_scan_range_t *range[CT_MAX_PARAL_QUERY]; +} ctc_index_paral_range_t; + typedef struct { uint64_t ignore : 1; uint64_t no_foreign_key_check : 1; @@ -535,6 +603,13 @@ typedef struct { uint32_t subpart_id; } ctc_part_t; +typedef struct en_ctcpart_scan_range { + ctc_scan_range_t range; + ctc_part_t part; + uint64_t query_scn; + uint64_t ssn; +} ctcpart_scan_range_t; + /* General Control Interface */ int srv_wait_instance_startuped(void); int ctc_alloc_inst_id(uint32_t *inst_id); @@ -580,8 +655,10 @@ int ctc_general_prefetch(ctc_handler_t *tch, uint8_t *records, uint16_t *record_ int ctc_free_session_cursors(ctc_handler_t *tch, uint64_t *cursors, int32_t csize); /* Transaction Related Interface */ -int ctc_trx_begin(ctc_handler_t *tch, ctc_trx_context_t trx_context, bool is_mysql_local); -int ctc_trx_commit(ctc_handler_t *tch, uint64_t *cursors, int32_t csize, bool *is_ddl_commit); +int ctc_trx_begin(ctc_handler_t *tch, ctc_trx_context_t trx_context, bool is_mysql_local, struct timeval begin_time, bool *enable_stat); +int ctc_statistic_begin(ctc_handler_t *tch,struct timeval begin_time, bool *enable_stat); +int ctc_trx_commit(ctc_handler_t *tch, uint64_t *cursors, int32_t csize, bool *is_ddl_commit, char *sql_str); +int ctc_statistic_commit(ctc_handler_t *tch,char *sql_str); int ctc_trx_rollback(ctc_handler_t *tch, uint64_t *cursors, int32_t csize); int ctc_srv_set_savepoint(ctc_handler_t *tch, const char *name); @@ -624,6 +701,9 @@ int ctc_truncate_partition(void *table_def, ddl_ctrl_t *ddl_ctrl); int ctc_rename_table(void *alter_def, ddl_ctrl_t *ddl_ctrl); int ctc_drop_table(void *drop_def, ddl_ctrl_t *ddl_ctrl); +int ctc_update_sample_size(uint32_t sample_size, bool need_persist); +int ctc_get_sample_size(uint32_t *sample_size); + int ctc_get_max_sessions_per_node(uint32_t *max_sessions); int ctc_get_serial_value(ctc_handler_t *tch, uint64_t *value, dml_flag_t flag); @@ -640,14 +720,29 @@ int ctc_broadcast_rewrite_sql(ctc_handler_t *tch, ctc_ddl_broadcast_request *bro /* Metadata Related Interface */ int ctc_check_db_table_exists(const char *db, const char *name, bool *is_exists); int ctc_search_metadata_status(bool *cantian_metadata_switch, bool *cantian_cluster_ready); - int ctc_invalidate_mysql_dd_cache(ctc_handler_t *tch, ctc_invalidate_broadcast_request *broadcast_req, int *err_code); int ctc_broadcast_mysql_dd_invalidate(ctc_handler_t *tch, ctc_invalidate_broadcast_request *broadcast_req); /* Disaster Recovery Related Interface*/ int ctc_set_cluster_role_by_cantian(bool is_slave); +void ctc_set_mysql_read_only(); +void ctc_reset_mysql_read_only(); int ctc_record_sql_for_cantian(ctc_handler_t *tch, ctc_ddl_broadcast_request *broadcast_req, bool allow_fail); + +/* Parallel Query Related Interface */ +int ctc_get_index_paral_schedule(ctc_handler_t *tch, uint64_t *query_scn, int *worker_count, + char* index_name, bool reverse, bool is_index_full, + ctc_scan_range_t *origin_scan_range, ctc_index_paral_range_t *index_paral_range); +int ctc_pq_index_read(ctc_handler_t *tch, record_info_t *record_info, index_key_info_t *index_info, + ctc_scan_range_t scan_range, ctc_select_mode_t mode, ctc_conds *cond, const bool is_replace, + uint64_t query_scn); + +int ctc_get_paral_schedule(ctc_handler_t *tch, uint64_t *query_scn, uint64_t *ssn, int *worker, + ctc_index_paral_range_t *paral_range); +int ctc_pq_set_cursor_range(ctc_handler_t *tch, ctc_page_id_t l_page, ctc_page_id_t r_page, uint64_t query_scn, + uint64_t ssn); + int ctc_query_cluster_role(bool *is_slave, bool *cantian_cluster_ready); int ctc_query_shm_file_num(uint32_t *shm_file_num); int ctc_query_shm_usage(uint32_t *shm_usage); diff --git a/storage/ctc/ctc_srv_mq_stub.cc b/storage/ctc/ctc_srv_mq_stub.cc index e57b0b3..7a90b42 100644 --- a/storage/ctc/ctc_srv_mq_stub.cc +++ b/storage/ctc/ctc_srv_mq_stub.cc @@ -526,7 +526,7 @@ int ctc_index_read(ctc_handler_t *tch, record_info_t *record_info, index_key_inf return result; } -int ctc_trx_begin(ctc_handler_t *tch, ctc_trx_context_t trx_context, bool is_mysql_local) { +int ctc_trx_begin(ctc_handler_t *tch, ctc_trx_context_t trx_context, bool is_mysql_local, struct timeval begin_time, bool *enable_stat) { void *shm_inst = get_one_shm_inst(tch); trx_begin_request *req = (trx_begin_request*)alloc_share_mem(shm_inst, sizeof(trx_begin_request)); if (req == NULL) { @@ -536,7 +536,8 @@ int ctc_trx_begin(ctc_handler_t *tch, ctc_trx_context_t trx_context, bool is_mys req->tch = *tch; req->trx_context = trx_context; req->is_mysql_local = is_mysql_local; - + req->begin_time = begin_time; + req->enable_stat = *enable_stat; int result = ERR_CONNECTION_FAILED; int ret = ctc_mq_deal_func(shm_inst, CTC_FUNC_TYPE_TRX_BEGIN, req, tch->msg_buf); *tch = req->tch; // 此处不管参天处理成功与否,都需要拷贝一次,避免session泄漏 @@ -546,8 +547,27 @@ int ctc_trx_begin(ctc_handler_t *tch, ctc_trx_context_t trx_context, bool is_mys free_share_mem(shm_inst, req); return result; } +int ctc_statistic_begin(ctc_handler_t *tch,struct timeval begin_time, bool *enable_stat) { + void *shm_inst = get_one_shm_inst(tch); + trx_begin_request *req = (trx_begin_request*)alloc_share_mem(shm_inst, sizeof(trx_begin_request)); + if (req == NULL) { + ctc_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(trx_begin_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + req->begin_time = begin_time; + req->enable_stat = *enable_stat; + int result = ERR_CONNECTION_FAILED; + int ret = ctc_mq_deal_func(shm_inst, CTC_FUNC_TYPE_STATISTIC_BEGIN, req, tch->msg_buf); + *tch = req->tch; // 此处不管参天处理成功与否,都需要拷贝一次,避免session泄漏 + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} -int ctc_trx_commit(ctc_handler_t *tch, uint64_t *cursors, int32_t csize, bool *is_ddl_commit) { +int ctc_trx_commit(ctc_handler_t *tch, uint64_t *cursors, int32_t csize, bool *is_ddl_commit, char *sql_str) { void *shm_inst = get_one_shm_inst(tch); trx_commit_request *req = (trx_commit_request*)alloc_share_mem(shm_inst, sizeof(trx_commit_request)); if (req == NULL) { @@ -557,7 +577,7 @@ int ctc_trx_commit(ctc_handler_t *tch, uint64_t *cursors, int32_t csize, bool *i req->tch = *tch; req->csize = csize; req->cursors = cursors; - + strncpy(req->sql, sql_str, MAX_DML_SQL_LEN - 1); int result = ERR_CONNECTION_FAILED; int ret = ctc_mq_deal_func(shm_inst, CTC_FUNC_TYPE_TRX_COMMIT, req, tch->msg_buf); *is_ddl_commit = req->is_ddl_commit; @@ -567,7 +587,23 @@ int ctc_trx_commit(ctc_handler_t *tch, uint64_t *cursors, int32_t csize, bool *i free_share_mem(shm_inst, req); return result; } - +int ctc_statistic_commit(ctc_handler_t *tch,char *sql_str) { + void *shm_inst = get_one_shm_inst(tch); + trx_commit_request *req = (trx_commit_request*)alloc_share_mem(shm_inst, sizeof(trx_commit_request)); + if (req == NULL) { + ctc_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(trx_commit_request)); + return ERR_ALLOC_MEMORY; + } + req->tch = *tch; + strncpy(req->sql, sql_str, MAX_DML_SQL_LEN - 1); + int result = ERR_CONNECTION_FAILED; + int ret = ctc_mq_deal_func(shm_inst, CTC_FUNC_TYPE_STATISTIC_COMMIT, req, tch->msg_buf); + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} int ctc_trx_rollback(ctc_handler_t *tch, uint64_t *cursors, int32_t csize) { void *shm_inst = get_one_shm_inst(tch); trx_rollback_request *req = (trx_rollback_request*)alloc_share_mem(shm_inst, sizeof(trx_rollback_request)); @@ -771,21 +807,16 @@ void ctc_cbo_stats_copy_from_shm(ctc_handler_t *tch, ctc_cbo_stats_table_t *ctc_ bool is_part_table = stats->part_cnt ? true : false; stats->is_updated = req->stats->is_updated; stats->records = req->stats->records; - stats->page_size = req->stats->page_size; memcpy(stats->ndv_keys, req->stats->ndv_keys, stats->key_len); uint num_columns = req->stats->msg_len / sizeof(ctc_cbo_stats_column_t); if (!is_part_table) { *tch = req->tch; ctc_cbo_stats_table->estimate_rows = req->ctc_cbo_stats_table->estimate_rows; - ctc_cbo_stats_table->avg_row_len = req->ctc_cbo_stats_table->avg_row_len; - ctc_cbo_stats_table->blocks = req->ctc_cbo_stats_table->blocks; ctc_cbo_stats_columns_copy(ctc_cbo_stats_table->columns, req->ctc_cbo_stats_table->columns, stats, num_columns); } else { for (uint i = 0; i < req->num_part_fetch; i++) { ctc_cbo_stats_table[i].estimate_rows = req->ctc_cbo_stats_table[i].estimate_rows; - ctc_cbo_stats_table[i].avg_row_len = req->ctc_cbo_stats_table[i].avg_row_len; - ctc_cbo_stats_table[i].blocks = req->ctc_cbo_stats_table[i].blocks; ctc_cbo_stats_columns_copy(ctc_cbo_stats_table[i].columns, req->ctc_cbo_stats_table[i].columns, stats, num_columns); } @@ -1659,6 +1690,152 @@ int ctc_record_sql_for_cantian(ctc_handler_t *tch, ctc_ddl_broadcast_request *br return result; } +// convert mysql side data to ctc message queue accepted request type and return; +int ctc_get_index_paral_schedule(ctc_handler_t *tch, uint64_t *query_scn, int *worker_count, + char* index_name, bool reverse, bool is_index_full, + ctc_scan_range_t *origin_scan_range, ctc_index_paral_range_t *index_paral_range) +{ + void *shm_inst = get_one_shm_inst(tch); + + get_index_paral_schedule_request *req = (get_index_paral_schedule_request*) + alloc_share_mem(shm_inst, sizeof(get_index_paral_schedule_request)); + if (req == NULL) { + ctc_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, + sizeof(get_index_paral_schedule_request)); + return ERR_ALLOC_MEMORY; + } + memset(req, 0, sizeof(get_index_paral_schedule_request)); + + req->tch = *tch; + req->worker_count = *worker_count; + memcpy(&req->index_name, index_name, sizeof(char) * (CTC_MAX_KEY_NAME_LENGTH + 1)); + req->scan_range = origin_scan_range; + req->query_scn = *query_scn; + req->reverse = reverse; + req->is_index_full = is_index_full; + // the index_paral_range is allocated outside this ctc_get_index_paral_schedule + // to avoid multiple redundent malloc-free pair in mrr scan. + req->index_paral_range = index_paral_range; + + int ret = ctc_mq_deal_func(shm_inst, CTC_FUNC_TYPE_GET_INDEX_PARAL_SCHEDULE, req, tch->msg_buf); + *tch = req->tch; + *query_scn = req->query_scn; + *worker_count = req->worker_count; + + free_share_mem(shm_inst, req); + if (ret == CT_SUCCESS) { + return req->result; + } + return ret; +} + +int ctc_pq_index_read(ctc_handler_t *tch, record_info_t *record_info, index_key_info_t *index_info, + ctc_scan_range_t scan_range, + ctc_select_mode_t mode, ctc_conds *cond, const bool is_replace, uint64_t query_scn) +{ + if (index_info == NULL) { + return ERR_GENERIC_INTERNAL_ERROR; + } + + void *shm_inst = get_one_shm_inst(tch); + pq_index_read_request *req = (pq_index_read_request*)alloc_share_mem(shm_inst, sizeof(pq_index_read_request)); + if (req == NULL) { + ctc_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(pq_index_read_request)); + return ERR_ALLOC_MEMORY; + } + memset(req, 0, sizeof(pq_index_read_request)); + + req->tch = *tch; + req->record = record_info->record; + req->record_len = 0; + req->mode = mode; + req->cond = cond; + req->is_replace = is_replace; + req->result = 0; + req->action = index_info->action; + req->need_init = index_info->need_init; + req->query_scn = query_scn; + + // the pointer in req->scan_range.{l/r}_key.buf will point to invalid address in cantian side. + memcpy(&req->scan_range, &scan_range, sizeof(ctc_scan_range_t)); + memcpy(&req->index_name, index_info->index_name, sizeof(char) * (CTC_MAX_KEY_NAME_LENGTH + 1)); + int result = ERR_CONNECTION_FAILED; + int ret = ctc_mq_deal_func(shm_inst, CTC_FUNC_TYPE_PQ_INDEX_READ, req, tch->msg_buf); + *tch = req->tch; + tch->sql_stat_start = req->tch.sql_stat_start; + if (ret == CT_SUCCESS) { + if (req->result == CT_SUCCESS) { + record_info->record_len = req->record_len; + assert(record_info->record_len < BIG_RECORD_SIZE); + } + result = req->result; + index_info->need_init = req->need_init; + } + + free_share_mem(shm_inst, req); + + return result; +} + +int ctc_pq_set_cursor_range(ctc_handler_t *tch, ctc_page_id_t l_page, ctc_page_id_t r_page, + uint64_t query_scn, uint64_t ssn) +{ + void *shm_inst = get_one_shm_inst(tch); + set_cursor_range_requst *req = (set_cursor_range_requst*)alloc_share_mem(shm_inst, sizeof(set_cursor_range_requst)); + if (req == NULL) { + ctc_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(set_cursor_range_requst)); + return ERR_ALLOC_MEMORY; + } + + req->tch = *tch; + req->l_page = l_page; + req->r_page = r_page; + req->query_scn = query_scn; + req->ssn = ssn; + int ret = ctc_mq_deal_func(shm_inst, CTC_FUNC_TYPE_PQ_SET_CURSOR_RANGE, req, tch->msg_buf); + *tch = req->tch; + free_share_mem(shm_inst, req); + if (ret == CT_SUCCESS) { + return req->result; + } + return ret; +} + +// this method call ct side for spliting a full table per-page scan to multi thread tasks +// the arg *paral_range should pointing at a mem range within shared memory. +int ctc_get_paral_schedule(ctc_handler_t *tch, uint64_t *query_scn, uint64_t *ssn, int *worker, + ctc_index_paral_range_t *paral_range) +{ + void *shm_inst = get_one_shm_inst(tch); + + get_paral_schedule_request *req = (get_paral_schedule_request*) + alloc_share_mem(shm_inst, sizeof(get_paral_schedule_request)); + if (req == NULL) { + ctc_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(get_paral_schedule_request)); + return ERR_ALLOC_MEMORY; + } + memset(req, 0, sizeof(get_paral_schedule_request)); + + req->tch = *tch; + req->query_scn = *query_scn; + req->paral_range = paral_range; + req->worker_count = *worker; + req->ssn = *ssn; + + int result = ERR_CONNECTION_FAILED; + int ret = ctc_mq_deal_func(shm_inst, CTC_FUNC_TYPE_GET_PARAL_SCHEDULE, req, tch->msg_buf); + + *tch = req->tch; + *worker = req->worker_count; + *query_scn = req->query_scn; + *ssn = req->ssn; + if (ret == CT_SUCCESS) { + result = req->result; + } + free_share_mem(shm_inst, req); + return result; +} + int ctc_query_cluster_role(bool *is_slave, bool *cantian_cluster_ready) { void *shm_inst = get_one_shm_inst(NULL); query_cluster_role_request *req = (query_cluster_role_request*) alloc_share_mem(shm_inst, sizeof(query_cluster_role_request)); @@ -1680,6 +1857,48 @@ int ctc_query_cluster_role(bool *is_slave, bool *cantian_cluster_ready) { return result; } +int ctc_update_sample_size(uint32_t sample_size, bool need_persist) +{ + void *shm_inst = get_one_shm_inst(nullptr); + + update_sample_size_request *req = (update_sample_size_request* )alloc_share_mem(shm_inst, sizeof(update_sample_size_request)); + if (req == nullptr) { + ctc_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(update_sample_size_request)); + return ERR_ALLOC_MEMORY; + } + req->sample_size = sample_size; + req->need_persist = need_persist; + + int res = ctc_mq_deal_func(shm_inst, CTC_FUNC_TYPE_UPDATE_SAMPLE_SIZE, req, nullptr); + if (res != CT_SUCCESS) { + ctc_log_error("ctc_mq_deal_func CTC_FUNC_TYPE_UPDATE_SAMPLE_SIZE failed"); + } + free_share_mem(shm_inst, req); + + return res; +} + +int ctc_get_sample_size(uint32_t *sample_size) +{ + void *shm_inst = get_one_shm_inst(nullptr); + + uint32_t *req = (uint32_t*)alloc_share_mem(shm_inst, sizeof(uint32_t)); + if (req == nullptr) { + ctc_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(uint32_t)); + return ERR_ALLOC_MEMORY; + } + + int res = ctc_mq_deal_func(shm_inst, CTC_FUNC_TYPE_GET_SAMPLE_SIZE, req, nullptr); + if (res != CT_SUCCESS) { + ctc_log_error("ctc_mq_deal_func CTC_FUNC_TYPE_GET_SAMPLE_SIZE failed"); + } + *sample_size = *req; + ctc_log_system("[ctc_get_sample_size] size(%u)", *sample_size); + free_share_mem(shm_inst, req); + + return res; +} + int ctc_query_shm_file_num(uint32_t *shm_file_num) { void *shm_inst = get_one_shm_inst(NULL); diff --git a/storage/ctc/ctc_stats.cc b/storage/ctc/ctc_stats.cc index 6d3f77d..3dc78ba 100644 --- a/storage/ctc/ctc_stats.cc +++ b/storage/ctc/ctc_stats.cc @@ -121,7 +121,7 @@ bool ctc_stats::get_statistics_enabled() { void ctc_stats::set_statistics_enabled(const bool enabled) { if (enabled && !m_statistics_enabled.load()) { - for (int i = 0; i < CTC_FUNC_TYPE_NUMBER; i++) { + for (int i = 0; i < EVENT_TYPE_COUNT; i++) { for (int hash_id = 0; hash_id < EVENT_TRACKING_GROUP; hash_id++) { m_calls[i][hash_id] = 0; m_use_time[i][hash_id] = 0; @@ -134,7 +134,6 @@ void ctc_stats::set_statistics_enabled(const bool enabled) { void ctc_stats::gather_stats(const enum EVENT_TRACKING type, const uint64_t start_cycles) { if (clock_frequency == 0) { - ctc_log_error("[TSE STATS] clock frequency is not initialized."); return; } uint64_t use_time = rdtsc() - start_cycles; diff --git a/storage/ctc/ctc_util.cc b/storage/ctc/ctc_util.cc index 4a739d2..a3c2c4b 100644 --- a/storage/ctc/ctc_util.cc +++ b/storage/ctc/ctc_util.cc @@ -163,96 +163,109 @@ int ctc_set_cond_field_size(const field_cnvrt_aux_t *mysql_info, ctc_conds *cond return CT_SUCCESS; } -int ctc_fill_cond_field_data_num(ctc_handler_t m_tch, Item *items, Field *mysql_field, - const field_cnvrt_aux_t *mysql_info, ctc_conds *cond) { - int ret = CT_SUCCESS; - void *data = nullptr; - bool is_alloc_data = CT_FALSE; - Item_func_comparison *item_func_comparison = dynamic_cast(items); - CTC_RET_ERR_IF_NULL(item_func_comparison); - switch (mysql_info->ddl_field_type) { - case CTC_DDL_TYPE_LONG: - case CTC_DDL_TYPE_LONGLONG: { - Item_func *item_func = dynamic_cast(items); - CTC_RET_ERR_IF_NULL(item_func); - longlong val; - if ((item_func->arguments()[1])->type() == Item::CACHE_ITEM) { - Item_cache_int *item_cache_int = dynamic_cast(item_func_comparison->arguments()[1]); - CTC_RET_ERR_IF_NULL(item_cache_int); - val = item_cache_int->val_int(); - } else { - Item_int *item_int = dynamic_cast(item_func_comparison->arguments()[1]); - CTC_RET_ERR_IF_NULL(item_int); - val = item_int->val_int(); - } - data = (uchar *)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(longlong), MYF(MY_WME)); - if (data == nullptr) { - ctc_log_error("[ctc_fill_cond_field_data_num]alloc mem failed, size(%ld)", sizeof(longlong)); - my_error(ER_OUT_OF_RESOURCES, MYF(0), "COND FIELD DATA"); - return CT_ERROR; - } - is_alloc_data = CT_TRUE; - memcpy(data, &val, sizeof(longlong)); - break; - } - case CTC_DDL_TYPE_DOUBLE: { - Item_float *item_float = dynamic_cast(item_func_comparison->arguments()[1]); - CTC_RET_ERR_IF_NULL(item_float); - data = &item_float->value; - break; - } - case CTC_DDL_TYPE_NEWDECIMAL: { - const int scale = mysql_field->decimals(); - Field_new_decimal *field_new_decimal = dynamic_cast(mysql_field); - CTC_RET_ERR_IF_NULL(field_new_decimal); - const int prec = field_new_decimal->precision; - int binary_size = my_decimal_get_binary_size(prec, scale); - uchar *buff = new uchar[binary_size]; - Item_decimal *item_decimal = dynamic_cast(item_func_comparison->arguments()[1]); - CTC_RET_ERR_IF_NULL(item_decimal); - my_decimal *d = item_decimal->val_decimal(nullptr); - my_decimal2binary(E_DEC_FATAL_ERROR, d, buff, prec, scale); - data = (uchar *)my_malloc(PSI_NOT_INSTRUMENTED, binary_size, MYF(MY_WME)); - if (data == nullptr) { - ctc_log_error("[ctc_fill_cond_field_data_num]alloc mem failed, size(%d)", binary_size); - my_error(ER_OUT_OF_RESOURCES, MYF(0), "COND FIELD DATA"); - return CT_ERROR; - } - is_alloc_data = CT_TRUE; - memcpy(data, buff, binary_size); - delete[] buff; - break; - } - default: - ctc_log_error("[ctc_copy_cond_field_data]unsupport sql_data_type %d", mysql_info->sql_data_type); - assert(0); - return CT_ERROR; +static int cond_fill_null(Item *item, ctc_conds *cond, Field **, ctc_handler_t , + ctc_cond_list *, bool , en_ctc_func_type_t *) { + cond->cond_type = CTC_CONST_EXPR; + cond->field_info.null_value = item->null_value; + cond->field_info.field_type = CTC_DDL_TYPE_NULL; + cond->field_info.field_size = 0; + return CT_SUCCESS; +} + +int ctc_cond_fill_data_int(ctc_conds *cond, longlong val, ctc_handler_t m_tch, bool is_unsigned) { + cond->field_info.field_size = sizeof(int64_t); + cond->field_info.field_value = ctc_alloc_buf(&m_tch, cond->field_info.field_size); + if (cond->field_info.field_value == nullptr) { + ctc_log_error("ctc_fill_cond_leaf_data_int: alloc field_data error, size(%u).", cond->field_info.field_size); + return CT_ERROR; } + + *(int64_t *)cond->field_info.field_value = val; + cond->field_info.field_type = CTC_DDL_TYPE_LONGLONG; + cond->field_info.is_unsigned = is_unsigned; + return CT_SUCCESS; +} + +int cond_fill_int(Item *item, ctc_conds *cond, Field **, ctc_handler_t m_tch, + ctc_cond_list *, bool , en_ctc_func_type_t *) { + cond->cond_type = CTC_CONST_EXPR; + Item_int *item_int = dynamic_cast(item); + CTC_RET_ERR_IF_NULL(item_int); + cond->field_info.null_value = item_int->null_value; + if (cond->field_info.null_value) { + return CT_SUCCESS; + } + return ctc_cond_fill_data_int(cond, item_int->val_int(), m_tch, item_int->unsigned_flag); +} + +int cond_fill_real(Item *item, ctc_conds *cond, Field **, ctc_handler_t m_tch, + ctc_cond_list *, bool , en_ctc_func_type_t *) { + cond->cond_type = CTC_CONST_EXPR; + cond->field_info.field_type = CTC_DDL_TYPE_DOUBLE; + Item_float *item_float = dynamic_cast(item); + CTC_RET_ERR_IF_NULL(item_float); + cond->field_info.null_value = item_float->null_value; + if (cond->field_info.null_value) { + return CT_SUCCESS; + } + cond->field_info.field_size = sizeof(double); + cond->field_info.field_value = ctc_alloc_buf(&m_tch, cond->field_info.field_size); + if (cond->field_info.field_value == nullptr) { + ctc_log_error("ctc_fill_cond_leaf_data_int: alloc field_data error, size(%u).", cond->field_info.field_size); + return CT_ERROR; + } + *(double *)cond->field_info.field_value = item_float->value; + return CT_SUCCESS; +} + +int cond_fill_decimal(Item *item, ctc_conds *cond, Field **, ctc_handler_t m_tch, + ctc_cond_list *, bool , en_ctc_func_type_t *) { + cond->cond_type = CTC_CONST_EXPR; + cond->field_info.field_type = CTC_DDL_TYPE_DECIMAL; + Item_decimal *item_decimal = dynamic_cast(item); + CTC_RET_ERR_IF_NULL(item_decimal); + cond->field_info.null_value = item_decimal->null_value; + if (cond->field_info.null_value) { + return CT_SUCCESS; + } + const int scale = item_decimal->decimals; + my_decimal *d = item_decimal->val_decimal(nullptr); + const int prec = d->precision(); + int binary_size = my_decimal_get_binary_size(prec, scale); + + uchar *data = (uchar *)my_malloc(PSI_NOT_INSTRUMENTED, binary_size, MYF(MY_WME)); + if (data == nullptr) { + ctc_log_error("[ctc_fill_cond_field_data_num]alloc mem failed, size(%d)", binary_size); + my_error(ER_OUT_OF_RESOURCES, MYF(0), "COND FIELD DATA"); + return CT_ERROR; + } + my_decimal2binary(E_DEC_FATAL_ERROR, d, data, prec, scale); uchar cantian_ptr[DECIMAL_MAX_STR_LENGTH + 1]; - ret = convert_numeric_to_cantian(mysql_info, (const uchar *)data, cantian_ptr, mysql_field, - (uint32_t *)(&cond->field_info.field_size)); + if (decimal_mysql_to_cantian(data, cantian_ptr, prec, scale, (uint32_t *)(&cond->field_info.field_size))) { + my_free(data); + return CT_ERROR; + } + cond->field_info.field_value = ctc_alloc_buf(&m_tch, cond->field_info.field_size); if (cond->field_info.field_size > 0 && cond->field_info.field_value == nullptr) { ctc_log_error("ctc_fill_cond_field: alloc field_data error, size(%u).", cond->field_info.field_size); + my_free(data); return CT_ERROR; } memcpy(cond->field_info.field_value, cantian_ptr, cond->field_info.field_size); - if (is_alloc_data) { - my_free(data); - is_alloc_data = CT_FALSE; - } - return ret; + my_free(data); + return CT_SUCCESS; } -void refill_cond_type_date(MYSQL_TIME ltime, ctc_conds *cond) { +void refill_cond_type_date(MYSQL_TIME ltime, en_ctc_func_type_t *functype) { if (!ltime.hour || !ltime.minute || !ltime.second || !ltime.second_part) { - switch (cond->func_type) { + switch (*functype) { case CTC_LT_FUNC: - cond->func_type = CTC_LE_FUNC; + *functype = CTC_LE_FUNC; break; case CTC_NE_FUNC: - cond->func_type = CTC_ISNOTNULL_FUNC; + *functype = CTC_ISNOTNULL_FUNC; break; default: break; @@ -260,38 +273,44 @@ void refill_cond_type_date(MYSQL_TIME ltime, ctc_conds *cond) { } } -int ctc_fill_cond_field_data_date(ctc_handler_t m_tch, const field_cnvrt_aux_t *mysql_info, +int ctc_fill_cond_field_data_date(ctc_handler_t m_tch, enum_field_types datatype, en_ctc_func_type_t *functype, MYSQL_TIME ltime, date_detail_t *date_detail, ctc_conds *cond) { + cond->cond_type = CTC_CONST_EXPR; + cond->field_info.field_size = sizeof(int64_t); int ret = CT_SUCCESS; cond->field_info.field_value = ctc_alloc_buf(&m_tch, cond->field_info.field_size); - if (cond->field_info.field_size > 0 && cond->field_info.field_value == nullptr) { + if (cond->field_info.field_value == nullptr) { ctc_log_error("ctc_fill_cond_field: alloc field_data error, size(%u).", cond->field_info.field_size); return CT_ERROR; } uchar my_ptr[8] = {0}; longlong ll; - switch (mysql_info->mysql_field_type) { + switch (datatype) { case MYSQL_TYPE_TIME: + cond->field_info.field_type = CTC_DDL_TYPE_TIME; ll = TIME_to_longlong_time_packed(ltime); my_time_packed_to_binary(ll, my_ptr, DATETIME_MAX_DECIMALS); memcpy(cond->field_info.field_value, my_ptr, cond->field_info.field_size); return ret; case MYSQL_TYPE_DATETIME: + cond->field_info.field_type = CTC_DDL_TYPE_DATETIME; ll = TIME_to_longlong_datetime_packed(ltime); my_datetime_packed_to_binary(ll, my_ptr, DATETIME_MAX_DECIMALS); memcpy(cond->field_info.field_value, my_ptr, cond->field_info.field_size); return ret; case MYSQL_TYPE_DATE: + cond->field_info.field_type = CTC_DDL_TYPE_DATE; my_date_to_binary(<ime, my_ptr); memcpy(cond->field_info.field_value, my_ptr, cond->field_info.field_size); - refill_cond_type_date(ltime, cond); + refill_cond_type_date(ltime, functype); return ret; case MYSQL_TYPE_TIMESTAMP: { + cond->field_info.field_type = CTC_DDL_TYPE_TIMESTAMP; if (!check_zero_time_ltime(ltime)) { THD *thd = current_thd; int warnings = 0; @@ -305,18 +324,48 @@ int ctc_fill_cond_field_data_date(ctc_handler_t m_tch, const field_cnvrt_aux_t * assert((warnings == EOK) || (warnings == MYSQL_TIME_WARN_TRUNCATED)); my_tz_UTC->gmt_sec_to_TIME(<ime, tm); } - /* fall through */ + break; } - + case MYSQL_TYPE_YEAR: default: - ret = assign_mysql_date_detail(mysql_info->mysql_field_type, ltime, date_detail); - if (ret != CT_SUCCESS) { - return ret; - } - cm_encode_date(date_detail, (date_t *)cond->field_info.field_value); - return ret; + cond->field_info.field_type = CTC_DDL_TYPE_YEAR; + break; + } + + ret = assign_mysql_date_detail(datatype, ltime, date_detail); + if (ret != CT_SUCCESS) { + return ret; } + cm_encode_date(date_detail, (date_t *)cond->field_info.field_value); + return ret; +} +int cond_fill_date(Item *item, ctc_conds *cond, Field **, ctc_handler_t m_tch, + ctc_cond_list *, bool , en_ctc_func_type_t *functype) { + MYSQL_TIME ltime = {0, 0, 0, 0, 0, 0, 0, 0, MYSQL_TIMESTAMP_ERROR, 0}; + date_detail_t date_detail = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + enum_field_types datatype = item->data_type(); + if (datatype == MYSQL_TYPE_YEAR) { + Item_int *item_int = dynamic_cast(item); + CTC_RET_ERR_IF_NULL(item_int); + ltime.year = item_int->value; + ltime.month = 1; + ltime.day = 1; + ltime.hour = 0; + ltime.minute = 0; + ltime.second = 0; + ltime.second_part = 0; + ltime.neg = false; + } else { + Item_func *item_date_func = dynamic_cast(item); + CTC_RET_ERR_IF_NULL(item_date_func); + Item_date_literal *item_date_literal = (Item_date_literal *)(item_date_func); + CTC_RET_ERR_IF_NULL(item_date_literal); + if (item_date_literal->get_date(<ime, TIME_FUZZY_DATE)) { + return CT_ERROR; + } + } + return ctc_fill_cond_field_data_date(m_tch, datatype, functype, ltime, &date_detail, cond); } void update_value_by_charset(char *data, uint16 *size, uint16 bytes) { @@ -341,21 +390,21 @@ int ctc_get_column_cs(const CHARSET_INFO *cs) { return cs->number; } -int ctc_fill_cond_field_data_string(ctc_handler_t m_tch, Item_func *item_func, - ctc_conds *cond, bool no_backslash) { - if ((item_func->arguments()[1])->type() == Item::NULL_ITEM) { - cond->field_info.null_value = true; - return CT_SUCCESS; - } - Item_field *item_field = dynamic_cast((item_func)->arguments()[0]); - CTC_RET_ERR_IF_NULL(item_field); - uint cslen = item_field->collation.collation->mbminlen; - cond->field_info.collate_id = ctc_get_column_cs(item_field->collation.collation); +int cond_fill_string(Item *item, ctc_conds *cond, Field **, ctc_handler_t m_tch, + ctc_cond_list *, bool no_backslash, en_ctc_func_type_t *functype) { + cond->cond_type = CTC_CONST_EXPR; + cond->field_info.field_type = CTC_DDL_TYPE_VARCHAR; + cond->field_info.collate_id = ctc_get_column_cs(item->collation.collation); if (no_backslash) { cond->field_info.no_backslash = true; } - Item_string *item_string = dynamic_cast(item_func->arguments()[1]); + Item_string *item_string = dynamic_cast(item); CTC_RET_ERR_IF_NULL(item_string); + cond->field_info.null_value = item_string->null_value; + if (cond->field_info.null_value) { + return CT_SUCCESS; + } + uint cslen = item_string->collation.collation->mbminlen; String *item_str = item_string->val_str(nullptr); cond->field_info.field_size = item_str->length(); void *data = item_str->ptr(); @@ -366,84 +415,53 @@ int ctc_fill_cond_field_data_string(ctc_handler_t m_tch, Item_func *item_func, } memset(cond->field_info.field_value, 0, cond->field_info.field_size); memcpy(cond->field_info.field_value, data, cond->field_info.field_size); - if(cond->func_type == CTC_LIKE_FUNC) { + if(*functype == CTC_LIKE_FUNC) { update_value_by_charset((char *)cond->field_info.field_value, &cond->field_info.field_size, cslen - 1); } return CT_SUCCESS; } -int ctc_fill_cond_field_data(ctc_handler_t m_tch, Item *items, Field *mysql_field, - const field_cnvrt_aux_t *mysql_info, ctc_conds *cond) { - int ret = CT_SUCCESS; - Item_func *item_func = dynamic_cast(items); - CTC_RET_ERR_IF_NULL(item_func); - Item_func_comparison *item_func_comparison = dynamic_cast(items); - CTC_RET_ERR_IF_NULL(item_func_comparison); - if ((item_func->arguments()[1])->type() == Item::CACHE_ITEM) { - Item_cache *item_cache = dynamic_cast(item_func_comparison->arguments()[1]); - CTC_RET_ERR_IF_NULL(item_cache); - cond->field_info.null_value = !item_cache->has_value(); - } else { - cond->field_info.null_value = item_func_comparison->arguments()[1]->null_value; - } +int cond_fill_cache(Item *item, ctc_conds *cond, Field **, ctc_handler_t m_tch, + ctc_cond_list *, bool , en_ctc_func_type_t *) { + cond->cond_type = CTC_CONST_EXPR; + Item_cache *item_cache = dynamic_cast(item); + CTC_RET_ERR_IF_NULL(item_cache); + + cond->field_info.null_value = !item_cache->has_value(); if (cond->field_info.null_value) { return CT_SUCCESS; } - - switch (mysql_info->sql_data_type) { - case NUMERIC_DATA: - ret = ctc_fill_cond_field_data_num(m_tch, items, mysql_field, mysql_info, cond); - break; - case DATETIME_DATA:{ - MYSQL_TIME ltime; - date_detail_t date_detail; - memset(&date_detail, 0, sizeof(date_detail_t)); - Item_func_comparison *item_func_comparison = dynamic_cast(items); - CTC_RET_ERR_IF_NULL(item_func_comparison); - if (mysql_info->mysql_field_type == MYSQL_TYPE_YEAR) { - Item_int *item_int = dynamic_cast(item_func_comparison->arguments()[1]); - CTC_RET_ERR_IF_NULL(item_int); - ltime.year = item_int->value; - ltime.month = 1; - ltime.day = 1; - ltime.hour = 0; - ltime.minute = 0; - ltime.second = 0; - ltime.second_part = 0; - ltime.neg = false; - } else { - Item_func *item_date_func = dynamic_cast(item_func->arguments()[1]); - CTC_RET_ERR_IF_NULL(item_date_func); - Item_date_literal *item_date_literal = (Item_date_literal *)(item_date_func); - CTC_RET_ERR_IF_NULL(item_date_literal); - if (item_date_literal->get_date(<ime, TIME_FUZZY_DATE)) { - return CT_ERROR; - } - } - ret = ctc_fill_cond_field_data_date(m_tch, mysql_info, ltime, &date_detail, cond); - break; - } - case STRING_DATA:{ - ret = ctc_fill_cond_field_data_string(m_tch, item_func, cond, false); + + int ret; + switch (item_cache->result_type()) { + case INT_RESULT: { + Item_cache_int *cache_int = dynamic_cast(item); + CTC_RET_ERR_IF_NULL(cache_int); + ret = ctc_cond_fill_data_int(cond, cache_int->val_int(), m_tch, cache_int->unsigned_flag); break; } - case LOB_DATA: - case UNKNOW_DATA: default: - ctc_log_error("[mysql2cantian]unsupport sql_data_type %d", mysql_info->sql_data_type); + ctc_log_error("cond_fill_cache: unsupport type of cache item."); return CT_ERROR; } return ret; } -int ctc_fill_cond_field(ctc_handler_t m_tch, Item *items, Field **field, ctc_conds *cond, bool no_backslash) { - Item_func *item_func = dynamic_cast(items); - CTC_RET_ERR_IF_NULL(item_func); - const char *field_name = item_func->arguments()[0]->item_name.ptr(); +int cond_fill_field(Item *item, ctc_conds *cond, Field **field, ctc_handler_t , + ctc_cond_list *, bool no_backslash, en_ctc_func_type_t *) { + Item_field *field_item = dynamic_cast(item); + CTC_RET_ERR_IF_NULL(field_item); + cond->cond_type = CTC_FIELD_EXPR; + // fill field no + const char *field_name = field_item->item_name.ptr(); cond->field_info.field_no = ctc_get_column_by_field(field, field_name); if (cond->field_info.field_no == INVALID_MAX_COLUMN) { return CT_ERROR; } + if (no_backslash) { + cond->field_info.no_backslash = true; + } + cond->field_info.collate_id = ctc_get_column_cs(field_item->collation.collation); Field *mysql_field = *(field + cond->field_info.field_no); enum_field_types type = mysql_field->type(); type = (type == MYSQL_TYPE_FLOAT) ? MYSQL_TYPE_DOUBLE : type; @@ -458,43 +476,124 @@ int ctc_fill_cond_field(ctc_handler_t m_tch, Item *items, Field **field, ctc_con } } cond->field_info.field_no -= gcol_cnt; - if (cond->func_type == CTC_ISNULL_FUNC || cond->func_type == CTC_ISNOTNULL_FUNC) { - return CT_SUCCESS; - } else if(cond->func_type == CTC_LIKE_FUNC) { - return ctc_fill_cond_field_data_string(m_tch, item_func, cond, no_backslash); - } - + + // fill field size if (ctc_set_cond_field_size(mysql_info, cond) != CT_SUCCESS) { return CT_ERROR; } - return ctc_fill_cond_field_data(m_tch, items, mysql_field, mysql_info, cond); + return CT_SUCCESS; +} + +static const cond_func_type_map g_cond_func_type[] = { + {Item_func::EQ_FUNC, CTC_EQ_FUNC, CTC_CMP_EXPR}, + {Item_func::EQUAL_FUNC, CTC_EQUAL_FUNC, CTC_CMP_EXPR}, + {Item_func::NE_FUNC, CTC_NE_FUNC, CTC_CMP_EXPR}, + {Item_func::LT_FUNC, CTC_LT_FUNC, CTC_CMP_EXPR}, + {Item_func::LE_FUNC, CTC_LE_FUNC, CTC_CMP_EXPR}, + {Item_func::GT_FUNC, CTC_GT_FUNC, CTC_CMP_EXPR}, + {Item_func::GE_FUNC, CTC_GE_FUNC, CTC_CMP_EXPR}, + {Item_func::LIKE_FUNC, CTC_LIKE_FUNC, CTC_LIKE_EXPR}, + {Item_func::ISNULL_FUNC, CTC_ISNULL_FUNC, CTC_NULL_EXPR}, + {Item_func::ISNOTNULL_FUNC, CTC_ISNOTNULL_FUNC, CTC_NULL_EXPR}, + {Item_func::COND_AND_FUNC, CTC_COND_AND_FUNC, CTC_LOGIC_EXPR}, + {Item_func::COND_OR_FUNC, CTC_COND_OR_FUNC, CTC_LOGIC_EXPR}, + {Item_func::XOR_FUNC, CTC_XOR_FUNC, CTC_LOGIC_EXPR}, + {Item_func::MOD_FUNC, CTC_MOD_FUNC, CTC_ARITHMATIC_EXPR}, + {Item_func::PLUS_FUNC, CTC_PLUS_FUNC, CTC_ARITHMATIC_EXPR}, + {Item_func::MINUS_FUNC, CTC_MINUS_FUNC, CTC_ARITHMATIC_EXPR}, + {Item_func::MUL_FUNC, CTC_MUL_FUNC, CTC_ARITHMATIC_EXPR}, + {Item_func::DIV_FUNC, CTC_DIV_FUNC, CTC_ARITHMATIC_EXPR}, + {Item_func::DATE_FUNC, CTC_DATE_FUNC, CTC_DATE_EXPR}, + {Item_func::DATETIME_LITERAL, CTC_DATE_FUNC, CTC_DATE_EXPR} +}; + +// Helper function to get condition type mapping +inline static const cond_func_type_map* get_cond_func_type_map(Item_func::Functype fc) { + for (const auto& mapping : g_cond_func_type) { + if (mapping.item_func_type == fc) { + return &mapping; + } + } + return nullptr; +} + +inline void set_cond_types(ctc_conds* conds, Item_func::Functype fc) { + const cond_func_type_map* mapping = get_cond_func_type_map(fc); + if (mapping) { + conds->cond_type = mapping->cond_type; + conds->func_type = mapping->func_type; + } else { + // Default values if mapping not found + conds->cond_type = CTC_UNKNOWN_EXPR; + conds->func_type = CTC_UNKNOWN_FUNC; + } } -int ctc_push_cond_list(ctc_handler_t m_tch, Item *items, Field **field, - ctc_cond_list *list, bool no_backslash) { - Item_cond *item_cond = dynamic_cast(items); +int cond_fill_func(Item *item, ctc_conds *cond, Field **field, ctc_handler_t m_tch, + ctc_cond_list *list, bool no_backslash, en_ctc_func_type_t *functype) { + Item_func *item_func = dynamic_cast(item); + CTC_RET_ERR_IF_NULL(item_func); + + Item_func::Functype fc = item_func->functype(); + set_cond_types(cond, fc); + if (cond->cond_type == CTC_DATE_EXPR) { + // fill in the parent functype in case of adjustment + return cond_fill_date(item, cond, field, m_tch, list, no_backslash, functype); + } + + Item **args = item_func->arguments(); + uint16_t size = item_func->argument_count(); + + for (uint16_t i = 0; i < size; i++) { + ctc_conds *sub_cond = (ctc_conds *)ctc_alloc_buf(&m_tch, sizeof(ctc_conds)); + if (sub_cond == nullptr) { + ctc_log_error("cond_fill_func: alloc ctc_conds error, size(%lu).", sizeof(ctc_conds)); + return CT_ERROR; + } + memset(sub_cond, 0, sizeof(ctc_conds)); + if (dfs_fill_conds(m_tch, args[i], field, sub_cond, no_backslash, &cond->func_type) != CT_SUCCESS) { + return CT_ERROR; + } + if (list->elements == 0) { + list->first = sub_cond; + } else { + list->last->next = sub_cond; + } + list->last = sub_cond; + (list->elements)++; + } + + return CT_SUCCESS; +} + +int cond_fill_cond(Item *item, ctc_conds *cond, Field **field, ctc_handler_t m_tch, + ctc_cond_list *list, bool no_backslash, en_ctc_func_type_t *) { + Item_cond *item_cond = dynamic_cast(item); CTC_RET_ERR_IF_NULL(item_cond); + + Item_func::Functype fc = item_cond->functype(); + set_cond_types(cond, fc); List *argument_list = item_cond->argument_list(); uint16_t size = argument_list->size(); list_node *node = argument_list->first_node(); for (uint16_t i = 0; i < size; i++) { - ctc_conds *cond = (ctc_conds *)ctc_alloc_buf(&m_tch, sizeof(ctc_conds)); - if (cond == nullptr) { - ctc_log_error("ctc_push_cond_list: alloc ctc_conds error, size(%lu).", sizeof(ctc_conds)); + ctc_conds *sub_cond = (ctc_conds *)ctc_alloc_buf(&m_tch, sizeof(ctc_conds)); + if (sub_cond == nullptr) { + ctc_log_error("cond_fill_cond: alloc ctc_conds error, size(%lu).", sizeof(ctc_conds)); return CT_ERROR; } - memset(cond, 0, sizeof(ctc_conds)); - if (dfs_fill_conds(m_tch, (Item *)(node->info), field, cond, no_backslash) != CT_SUCCESS) { + memset(sub_cond, 0, sizeof(ctc_conds)); + if (dfs_fill_conds(m_tch, (Item *)(node->info), field, sub_cond, no_backslash, NULL) != CT_SUCCESS) { return CT_ERROR; } if (list->elements == 0) { - list->first = cond; + list->first = sub_cond; } else { - list->last->next = cond; + list->last->next = sub_cond; } - list->last = cond; + list->last = sub_cond; (list->elements)++; node = node->next; } @@ -502,116 +601,600 @@ int ctc_push_cond_list(ctc_handler_t m_tch, Item *items, Field **field, return CT_SUCCESS; } -int ctc_push_cond_args(ctc_handler_t m_tch, Item *items, Field **field, - ctc_cond_list *list, bool no_backslash) { - Item_func *item_func = dynamic_cast(items); - CTC_RET_ERR_IF_NULL(item_func); +static bool is_supported_conds(Item *term, Item_func::Functype parent_type) { + if (parent_type != Item_func::COND_AND_FUNC && parent_type != Item_func::COND_OR_FUNC) { + /* + Unsupported push down condition, + e.g. select * from tbl where ((col1 < 1) and (col1 > 0)) = 1; + in which case the parent condition for + ((col1 < 1) and (col1 > 0)) is not AND/OR operator + */ + return false; + } + + Item_func *item_func = dynamic_cast(term); + if (item_func == nullptr) { + return false; + } + + Item_func::Functype functype = item_func->functype(); + + if (functype == Item_func::COND_AND_FUNC || + functype == Item_func::COND_OR_FUNC ) { + return true; + } + return false; +} + +static bool is_supported_funcs_like(Item_func *item_func, Item_func::Functype parent_type) { + if (parent_type != Item_func::COND_AND_FUNC && parent_type != Item_func::COND_OR_FUNC) { + return false; + } + /* + push down LIKE function only for simple condition, eg. + 'select * from tbl where col like "abc%"' + */ + Item_result cmp_context_next = item_func->arguments()[1]->cmp_context; + if (item_func->arguments()[1]->type() != Item::STRING_ITEM || cmp_context_next != STRING_RESULT) { + return false; + } + + if (item_func->arguments()[0]->type() != Item::FIELD_ITEM) { + return false; + } + + Item_func_like *like_func = dynamic_cast(item_func); + if (like_func == nullptr || like_func->escape_was_used_in_parsing() ) { + return false; + } + + Item_field *item_field = dynamic_cast(item_func->arguments()[0]); + if (item_field == nullptr) { + return false; + } + + if (!is_string_type(item_field->data_type())) { + return false; + } + + return true; +} + +static bool is_arithmetic_function(Item_func::Functype functype) { + switch (functype) { + case Item_func::PLUS_FUNC: + case Item_func::MINUS_FUNC: + case Item_func::MUL_FUNC: + case Item_func::DIV_FUNC: + case Item_func::MOD_FUNC: + return true; + default: + return false; + } +} + +static bool is_supported_funcs_arithmetic(Item_func *item_func, Item_func::Functype parent_type) { + if (parent_type == Item_func::COND_AND_FUNC || parent_type == Item_func::COND_OR_FUNC) { + /* + Unsupported push down condition, + eg. select * from tbl where (col1 + 1) and (col1 > 0); + In which case, condition (col1 + 1) is not comparision operation. + */ + return false; + } + + if (item_func->argument_count() != 2) { + return false; + } + + /* + push down arithmetic operation only for integer type, eg. + 'select * from tbl where col1 % 2 = 0;' + */ Item **args = item_func->arguments(); uint16_t size = item_func->argument_count(); + for (uint16_t i = 0; i < size; i++) { + if (args[i]->type() == Item::FIELD_ITEM) { + Item_field *item_field = dynamic_cast(args[i]); + if (item_field == nullptr) { + return false; + } + if (!is_integer_type(item_field->data_type())) { + return false; + } + } else if (args[i]->type() == Item::FUNC_ITEM) { + if (!is_arithmetic_function(dynamic_cast(args[i])->functype())) { + return false; + } + } else if (!(args[i]->type() == Item::INT_ITEM || + args[i]->type() == Item::CACHE_ITEM)) { + return false; + } + } + return true; +} + +static bool is_supported_funcs_logic(Item_func *item_func, Item_func::Functype parent_type) { + if (parent_type != Item_func::COND_AND_FUNC && parent_type != Item_func::COND_OR_FUNC) { + /* + Unsupported push down condition, + eg. select * from tbl where ((col1 < 1) and (col1 > 0))= 1; + */ + return false; + } + /* + push down logic operation only for comparison condition, eg. + 'select * from tbl where (col1 < 1) and (col1 > 0)' + 'select * from tbl where (col1 < 1) or (col1 > 0)' + 'select * from tbl where (col1 < 1) xor (col1 > 0)' + */ + if (item_func->argument_count() != 2) { + return false; + } + return true; + + Item **args = item_func->arguments(); + uint16_t size = item_func->argument_count(); for (uint16_t i = 0; i < size; i++) { - ctc_conds *cond = (ctc_conds *)ctc_alloc_buf(&m_tch, sizeof(ctc_conds)); - if (cond == nullptr) { - ctc_log_error("ctc_push_cond_args: alloc ctc_conds error, size(%lu).", sizeof(ctc_conds)); - return CT_ERROR; + if (args[i]->type() != Item::FUNC_ITEM) { + return false; } - memset(cond, 0, sizeof(ctc_conds)); - dfs_fill_conds(m_tch, args[i], field, cond, no_backslash); - if (list->elements == 0) { - list->first = cond; - } else { - list->last->next = cond; + Item_func *sub_item = dynamic_cast(args[i]); + const cond_func_type_map* mapping = get_cond_func_type_map(sub_item->functype()); + if (mapping == nullptr) { + return false; } - list->last = cond; - (list->elements)++; + if (mapping->cond_type == CTC_ARITHMATIC_EXPR || mapping->cond_type == CTC_DATE_EXPR) { + return false; + } + } + return true; +} + +static bool is_supported_funcs_null(Item_func *item_func, Item_func::Functype parent_type) { + if (parent_type != Item_func::COND_AND_FUNC && parent_type != Item_func::COND_OR_FUNC) { + return false; + } + /* + push down IS_NULL / IS_NOT_NULL function only for simple condition, eg. + 'select * from tbl where col is null' + */ + if (item_func->arguments()[0]->type() != Item::FIELD_ITEM) { + return false; + } + return true; +} + +static bool check_cmp_result(Item_field *item_field, Item *right) { + if (item_field == nullptr) { + return false; } + Item_result cmp_context_next = right->cmp_context; + Item::Type type = right->type(); - return CT_SUCCESS; + if (type == Item::NULL_ITEM) { + return true; + } + + if (item_field->data_type() == MYSQL_TYPE_YEAR) { + return type == Item::INT_ITEM && cmp_context_next == INT_RESULT; + } + + if (is_temporal_type(item_field->data_type())) { + if (!((right)->basic_const_item() && cmp_context_next == INT_RESULT)) { + return false; + } + if (item_field->data_type() == MYSQL_TYPE_TIMESTAMP) { + MYSQL_TIME ltime = {0, 0, 0, 0, 0, 0, 0, 0, MYSQL_TIMESTAMP_ERROR, 0}; + Item_func *item_date_func = dynamic_cast(right); + if (item_date_func == nullptr) { + return false; + } + Item_date_literal *item_date_literal = (Item_date_literal *)(item_date_func); + if (item_date_literal == nullptr) { + return false; + } + if (item_date_literal->get_date(<ime, TIME_FUZZY_DATE)) { + return false; + } + if (non_zero_date(ltime)) { + return ltime.year && ltime.month && ltime.day; + } + } + return true; + } + + if (is_string_type(item_field->data_type())) { + return type == Item::STRING_ITEM && cmp_context_next == STRING_RESULT; + } + + if (is_integer_type(item_field->data_type())) { + return (type == Item::INT_ITEM && cmp_context_next == INT_RESULT) || type == Item::CACHE_ITEM; + } + + if (is_numeric_type(item_field->data_type())) { + return (type == Item::REAL_ITEM || type == Item::DECIMAL_ITEM) && cmp_context_next != STRING_RESULT; + } + + return false; } -ctc_func_type_t item_func_to_ctc_func(Item_func::Functype fc) { - switch (fc) { - case (Item_func::Functype::EQUAL_FUNC): - return CTC_EQUAL_FUNC; - case (Item_func::Functype::EQ_FUNC): - return CTC_EQ_FUNC; - case (Item_func::Functype::NE_FUNC): - return CTC_NE_FUNC; - case (Item_func::Functype::LT_FUNC): - return CTC_LT_FUNC; - case (Item_func::Functype::LE_FUNC): - return CTC_LE_FUNC; - case (Item_func::Functype::GT_FUNC): - return CTC_GT_FUNC; - case (Item_func::Functype::GE_FUNC): - return CTC_GE_FUNC; - case (Item_func::Functype::ISNULL_FUNC): - return CTC_ISNULL_FUNC; - case (Item_func::Functype::ISNOTNULL_FUNC): - return CTC_ISNOTNULL_FUNC; - case (Item_func::Functype::LIKE_FUNC): - return CTC_LIKE_FUNC; - case (Item_func::Functype::NOT_FUNC): - return CTC_NOT_FUNC; - case (Item_func::Functype::COND_AND_FUNC): - return CTC_COND_AND_FUNC; - case (Item_func::Functype::COND_OR_FUNC): - return CTC_COND_OR_FUNC; - case (Item_func::Functype::XOR_FUNC): - return CTC_XOR_FUNC; +static bool is_supported_const(Item *term, Item_func::Functype parent_type) { + if (parent_type == Item_func::COND_AND_FUNC || parent_type == Item_func::COND_OR_FUNC) { + return false; + } + + switch (term->type()) { + case Item::INT_ITEM: + case Item::STRING_ITEM: + case Item::REAL_ITEM: + case Item::DECIMAL_ITEM: + case Item::NULL_ITEM: + return true; default: - return CTC_UNKNOWN_FUNC; + return false; } } -int dfs_fill_conds(ctc_handler_t m_tch, Item *items, Field **field, ctc_conds *conds, bool no_backslash) { - Item_func *item_func = dynamic_cast(items); - CTC_RET_ERR_IF_NULL(item_func); - Item_func::Functype fc = item_func->functype(); - conds->func_type = item_func_to_ctc_func(fc); - int ret = CT_SUCCESS; - ctc_cond_list *list; - - switch (conds->func_type) { - case CTC_COND_AND_FUNC: - case CTC_COND_OR_FUNC: - list = (ctc_cond_list *)ctc_alloc_buf(&m_tch, sizeof(ctc_cond_list)); - if (list == nullptr) { - ctc_log_error("ctc_fill_conds: alloc ctc_cond_list error, size(%lu).", sizeof(ctc_cond_list)); - return CT_ERROR; +static bool is_valid_cmp_operand(Item *operand1, Item *operand2, Item_func::Functype parent_type) { + if (operand1->type() == Item::FUNC_ITEM) { + Item_func *item_func = dynamic_cast(operand1); + if (item_func == nullptr) { + return false; + } + + Item_func::Functype functype = item_func->functype(); + const cond_func_type_map* mapping = get_cond_func_type_map(functype); + // Check if the function type exists in the g_cond_type array + if (mapping == nullptr) { + return false; + } + if (mapping->cond_type == CTC_ARITHMATIC_EXPR) { + if (operand2->type() == Item::INT_ITEM) { + return true; } - memset(list, 0, sizeof(ctc_cond_list)); - ret = ctc_push_cond_list(m_tch, items, field, list, no_backslash); - conds->cond_list = list; - break; - case CTC_NOT_FUNC: - case CTC_XOR_FUNC: - list = (ctc_cond_list *)ctc_alloc_buf(&m_tch, sizeof(ctc_cond_list)); - if (list == nullptr) { - ctc_log_error("ctc_fill_conds: alloc ctc_cond_list error, size(%lu).", sizeof(ctc_cond_list)); - return CT_ERROR; + if (operand2->type() == Item::CACHE_ITEM) { + return dynamic_cast(operand2)->result_type() == Item_result::INT_RESULT; } - memset(list, 0, sizeof(ctc_cond_list)); - ret = ctc_push_cond_args(m_tch, items, field, list, no_backslash); - conds->cond_list = list; - break; - case CTC_EQ_FUNC: - case CTC_EQUAL_FUNC: - case CTC_NE_FUNC: - case CTC_LT_FUNC: - case CTC_LE_FUNC: - case CTC_GE_FUNC: - case CTC_GT_FUNC: - case CTC_ISNULL_FUNC: - case CTC_ISNOTNULL_FUNC: - case CTC_LIKE_FUNC: - ret = ctc_fill_cond_field(m_tch, item_func, field, conds, no_backslash); + if (operand2->type() == Item::FIELD_ITEM) { + return is_integer_type(operand2->data_type()); + } + if (operand2->type() == Item::FUNC_ITEM) { + return is_arithmetic_function(dynamic_cast(operand2)->functype()); + } + return false; + } + return false; + } + + if (operand1->type() == Item::FIELD_ITEM) { + return check_cmp_result(dynamic_cast(operand1), operand2); + } + + return is_supported_const(operand2, parent_type); +} + +static bool is_supported_funcs_cmp(Item_func *item_func, Item_func::Functype parent_type) { + if (parent_type != Item_func::COND_AND_FUNC && parent_type != Item_func::COND_OR_FUNC) { + return false; + } + + if (item_func->argument_count() != 2) { + return false; + } + Item *left = item_func->arguments()[0]; + Item *right = item_func->arguments()[1]; + Item_func::Functype functype = item_func->functype(); + if (is_valid_cmp_operand(left, right, functype) || is_valid_cmp_operand(right, left, functype)) { + return true; + } + + return false; +} + +static bool is_supported_funcs_date(Item_func *, Item_func::Functype parent_type) { + if (parent_type == Item_func::COND_AND_FUNC || parent_type == Item_func::COND_OR_FUNC) { + return false; + } + return true; +} + +static bool is_supported_funcs(Item *term, Item_func::Functype parent_type) { + Item_func *item_func = dynamic_cast(term); + if (item_func == nullptr) { + return false; + } + + Item_func::Functype functype = item_func->functype(); + const cond_func_type_map* mapping = get_cond_func_type_map(functype); + // Check if the function type exists in the g_cond_type array + if (mapping == nullptr) { + return false; + } + switch (mapping->cond_type) { + case CTC_CMP_EXPR: + return is_supported_funcs_cmp(item_func, parent_type); + case CTC_LOGIC_EXPR: + return is_supported_funcs_logic(item_func, parent_type); + case CTC_NULL_EXPR: + return is_supported_funcs_null(item_func, parent_type); + case CTC_LIKE_EXPR: + return is_supported_funcs_like(item_func, parent_type); + case CTC_ARITHMATIC_EXPR: + return is_supported_funcs_arithmetic(item_func, parent_type); + case CTC_DATE_EXPR: + return is_supported_funcs_date(item_func, parent_type); + default: break; - case CTC_UNKNOWN_FUNC: + } + return false; +} + +static bool is_supported_cache(Item *term, Item_func::Functype parent_type) { + if (parent_type == Item_func::COND_AND_FUNC || parent_type == Item_func::COND_OR_FUNC) { + return false; + } + + if (term->result_type() == Item_result::INT_RESULT) { + return true; + } + return false; +} + +static bool is_supported_datatype_field(enum_field_types datatype) { + switch (datatype) { + case MYSQL_TYPE_JSON: + case MYSQL_TYPE_ENUM: + case MYSQL_TYPE_SET: + case MYSQL_TYPE_BIT: + case MYSQL_TYPE_NULL: + case MYSQL_TYPE_TYPED_ARRAY: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + case MYSQL_TYPE_BLOB: { + return false; + } default: - return CT_ERROR; + return true; } - return ret; +} + +static bool is_supported_field(Item *term, Item_func::Functype parent_type) { + if (parent_type == Item_func::COND_AND_FUNC || parent_type == Item_func::COND_OR_FUNC) { + return false; + } + + Item::Type type = term->type(); + // filter expressions + if (type != Item::FIELD_ITEM) { + return false; + } + + Item_field *item_field = dynamic_cast(term); + if (item_field == nullptr) { + return false; + } + + // filter generated column + if (item_field->field->is_gcol() || !item_field->field->part_of_prefixkey.is_clear_all()) { + return false; + } + + // filter unsupport datatype + if (!is_supported_datatype_field(item_field->field->real_type())) { + return false; + } + + if (item_field->data_type() == MYSQL_TYPE_STRING) { + if (item_field->collation.collation->pad_char == '\0') { + return false; + } + } + + if (parent_type == Item_func::ISNULL_FUNC || parent_type == Item_func::ISNOTNULL_FUNC) { + return true; + } + + const cond_func_type_map* mapping = get_cond_func_type_map(parent_type); + if (mapping == nullptr) { + return false; + } + + if (mapping->cond_type == CTC_CMP_EXPR && item_field->cmp_context == INVALID_RESULT) { + return false; + } + return true; +} + +static inline void push_all_cond_item(Item *term, Item *&pushed_cond, Item *&remainder_cond) { + pushed_cond = term; + remainder_cond = nullptr; +} + +static inline void remain_all_cond_item(Item *term, Item *&pushed_cond, Item *&remainder_cond) { + pushed_cond = nullptr; + remainder_cond = term; +} + +void push_func_item(Item *term, Item *&pushed_cond, Item *&remainder_cond) { + Item_func *cond = dynamic_cast(term); + if (cond == nullptr) { + return; + } + Item *operand; + // Item_result result_type; + for (uint i = 0; i < cond->argument_count(); i++) { + operand = cond->arguments()[i]; + Item *pushed = nullptr, *remainder = nullptr; + cond_push_term(operand, pushed, remainder, cond->functype()); + if (pushed == nullptr) { + // failed to push one of the terms, fails entire cond + remain_all_cond_item(cond, pushed_cond, remainder_cond); + return; + } + } + push_all_cond_item(cond, pushed_cond, remainder_cond); +} + +int create_and_conditions(Item_cond *cond, List pushed_list, + List remainder_list, Item *&pushed_cond, + Item *&remainder_cond) { + if (remainder_list.is_empty()) { + // Entire cond pushed, no remainder + pushed_cond = cond; + remainder_cond = nullptr; + return 0; + } + if (pushed_list.is_empty()) { + // Nothing pushed, entire 'cond' is remainder + pushed_cond = nullptr; + remainder_cond = cond; + return 0; + } + + // Condition was partly pushed, with some remainder + if (pushed_list.elements == 1) { + // Single boolean term pushed, return it + pushed_cond = pushed_list.head(); + } else { + // Construct an AND'ed condition of pushed boolean terms + pushed_cond = new Item_cond_and(pushed_list); + if (pushed_cond == nullptr) { + return 1; + } + } + + if (remainder_list.elements == 1) { + // A single boolean term as remainder, return it + remainder_cond = remainder_list.head(); + } else { + // Construct a remainder as an AND'ed condition of the boolean terms + remainder_cond = new Item_cond_and(remainder_list); + if (remainder_cond == nullptr) { + return 1; + } + } + return 0; +} + +int create_or_conditions(Item_cond *cond, List pushed_list, + List remainder_list, Item *&pushed_cond, + Item *&remainder_cond) { + assert(pushed_list.elements == cond->argument_list()->elements); + + if (remainder_list.is_empty()) { + // Entire cond pushed, no remainder + pushed_cond = cond; + remainder_cond = nullptr; + } else { + // When condition was partially pushed, we need to reevaluate + // original OR-cond on the server side: + remainder_cond = cond; + + // Construct an OR condition of pushed terms + pushed_cond = new Item_cond_or(pushed_list); + if (pushed_cond == nullptr){ + return 1; + } + } + return 0; +} + +void cond_push_boolean_term(Item *term, Item *&pushed_cond, Item *&remainder_cond) { + if (term->type() != Item::COND_ITEM) { + remain_all_cond_item(term, pushed_cond, remainder_cond); + return; + } + + List pushed_list; + List remainder_list; + Item_cond *cond = dynamic_cast(term); + if (cond == nullptr) { + return; + } + List_iterator li(*cond->argument_list()); + Item *operand; + bool is_and_condition = (cond->functype() == Item_func::COND_AND_FUNC); + while ((operand = li++)) { + Item *pushed = nullptr, *remainder = nullptr; + cond_push_term(operand, pushed, remainder, cond->functype()); + if (pushed == nullptr && !is_and_condition) { + remain_all_cond_item(cond, pushed_cond, remainder_cond); + return; + } + if (pushed != nullptr) pushed_list.push_back(pushed); + if (remainder != nullptr) remainder_list.push_back(remainder); + } + + if (is_and_condition) { + if (create_and_conditions(cond, pushed_list, remainder_list, pushed_cond, + remainder_cond)) { + remain_all_cond_item(cond, pushed_cond, remainder_cond); + return; + } + } else { + if (create_or_conditions(cond, pushed_list, remainder_list, pushed_cond, + remainder_cond)) { + remain_all_cond_item(cond, pushed_cond, remainder_cond); + return; + } + } +} + +const ctc_cond_push_map g_cond_push_map[] = { + {Item::FUNC_ITEM, is_supported_funcs, push_func_item, cond_fill_func}, + {Item::COND_ITEM, is_supported_conds, cond_push_boolean_term, cond_fill_cond}, + {Item::FIELD_ITEM, is_supported_field, push_all_cond_item, cond_fill_field}, + {Item::INT_ITEM, is_supported_const, push_all_cond_item, cond_fill_int}, + {Item::REAL_ITEM, is_supported_const, push_all_cond_item, cond_fill_real}, + {Item::DECIMAL_ITEM, is_supported_const, push_all_cond_item, cond_fill_decimal}, + {Item::STRING_ITEM, is_supported_const, push_all_cond_item, cond_fill_string}, + {Item::NULL_ITEM, is_supported_const, push_all_cond_item, cond_fill_null}, + {Item::CACHE_ITEM, is_supported_cache, push_all_cond_item, cond_fill_cache}, +}; + +// Helper function to get condition pushdown mapping +static const ctc_cond_push_map* get_cond_push_map(Item::Type type) { + for (const auto& mapping : g_cond_push_map) { + if (mapping.type == type) { + return &mapping; + } + } + return nullptr; +} + +void cond_push_term(Item *term, Item *&pushed_cond, Item *&remainder_cond, Item_func::Functype parent_type) { + Item::Type type = term->type(); + const ctc_cond_push_map* cond_map = get_cond_push_map(type); + if (cond_map != nullptr && cond_map->is_support(term, parent_type)) { + cond_map->push(term, pushed_cond, remainder_cond); + return; + } + remain_all_cond_item(term, pushed_cond, remainder_cond); +} + +int dfs_fill_conds(ctc_handler_t m_tch, Item *items, Field **field, ctc_conds *conds, + bool no_backslash, en_ctc_func_type_t *functype) { + Item::Type type = items->type(); + const ctc_cond_push_map* cond_map = get_cond_push_map(type); + if (cond_map == nullptr) { + return CT_ERROR; + } + + ctc_cond_list *list = (ctc_cond_list *)ctc_alloc_buf(&m_tch, sizeof(ctc_cond_list)); + if (list == nullptr) { + ctc_log_error("dfs_fill_conds: alloc ctc_cond_list error, size(%lu).", sizeof(ctc_cond_list)); + return CT_ERROR; + } + memset(list, 0, sizeof(ctc_cond_list)); + if (cond_map->fill(items, conds, field, m_tch, list, no_backslash, functype) != CT_SUCCESS) { + return CT_ERROR; + } + + conds->cond_list = list; + return CT_SUCCESS; } void cm_assert(bool condition) @@ -848,4 +1431,19 @@ longlong get_session_variable_int_value_with_range(THD *thd, return default_value; } return var_value; +} + +int32_t ctc_cmp_cantian_rowid(const rowid_t *rowid1, const rowid_t *rowid2) { + int32_t result = rowid1->file > rowid2->file ? 1 : (rowid1->file < rowid2->file ? (-1) : 0); + if (result != 0) { + return result; + } + + result = rowid1->page > rowid2->page ? 1 : (rowid1->page < rowid2->page ? (-1) : 0); + if (result != 0) { + return result; + } + + result = rowid1->slot > rowid2->slot ? 1 : (rowid1->slot < rowid2->slot ? (-1) : 0); + return result; } \ No newline at end of file diff --git a/storage/ctc/ctc_util.h b/storage/ctc/ctc_util.h index 12216ff..4591285 100644 --- a/storage/ctc/ctc_util.h +++ b/storage/ctc/ctc_util.h @@ -32,11 +32,21 @@ using namespace std; static unordered_set mysql_system_db{"information_schema", "mysql", "performance_schema", "sys"}; +typedef struct en_ctc_cond_func_type_map { + Item_func::Functype item_func_type; + ctc_func_type_t func_type; + ctc_cond_type_t cond_type; +} cond_func_type_map; + #define CM_IS_EMPTY_STR(str) (((str) == NULL) || ((str)[0] == 0)) #define CTC_GET_THD_DB_NAME(thd) (thd->db().str == NULL) ? nullptr : const_cast(thd->db().str) -#define CBO_STRING_MAX_LEN 16 +#ifndef WITH_CANTIAN + #define CBO_STRING_MAX_LEN 16 +#else + #define CBO_STRING_MAX_LEN 64 +#endif #define OFFSET_VARCHAR_TYPE 2 @@ -45,6 +55,52 @@ static unordered_set mysql_system_db{"information_schema", "mysql", "per #define SESSION_VARIABLE_VALUE_MAX_CREATE_INDEX_PARALLELISM 10 #define SESSION_VARIABLE_VALUE_DEFAULT_CREATE_INDEX_PARALLELISM -1 +#define ROWID_FILE_BITS 10 +#define ROWID_PAGE_BITS 30 +#define ROWID_SLOT_BITS 12 +#define ROWID_UNUSED_BITS 12 +#define ROWID_VALUE_BITS 52 +#pragma pack(4) +// cantian Row ID type identify a physical position of a row +typedef union st_rowid { + struct { + uint64_t value : ROWID_VALUE_BITS; + uint64_t unused1 : ROWID_UNUSED_BITS; + }; + + struct { + uint64_t file : ROWID_FILE_BITS; // file + uint64_t page : ROWID_PAGE_BITS; // page + uint64_t slot : ROWID_SLOT_BITS; // slot number + uint64_t unused2 : ROWID_UNUSED_BITS; + }; + + struct { + uint64_t vmid : 32; // virtual memory page id, dynamic view item, ... + uint64_t vm_slot : 16; // slot of virtual memory page, sub item + uint64_t vm_tag : 16; + }; + + struct { + uint32_t tenant_id : 16; + uint32_t curr_ts_num : 16; + uint32_t ts_id; + }; + + struct { + uint32_t group_id; + uint32_t attr_id; + }; + + struct { + uint32_t pos; + uint32_t bucket_id : 16; + uint32_t sub_id : 16; + }; +} rowid_t; +#pragma pack() + +int32_t ctc_cmp_cantian_rowid(const rowid_t *rowid1, const rowid_t *rowid2); void ctc_split_normalized_name(const char *file_name, char db[], size_t db_buf_len, char name[], size_t name_buf_len, bool *is_tmp_table); void ctc_copy_name(char to_name[], const char from_name[], size_t to_buf_len); @@ -52,21 +108,8 @@ bool ctc_check_ddl_sql_length(const string &query_str); string format_remote_errmsg(const char *err_msg); // utils for cond pushdown -int dfs_fill_conds(ctc_handler_t m_tch, Item *items, Field **field, ctc_conds *conds, bool no_backslash); -int ctc_push_cond_list(ctc_handler_t m_tch, Item *items, Field **field, ctc_cond_list *list, bool no_backslash); -int ctc_push_cond_args(ctc_handler_t m_tch, Item *items, Field **field, ctc_cond_list *list, bool no_backslash); -int ctc_fill_cond_field(Item *items, Field **field, ctc_conds *cond, bool no_backslash); -int ctc_set_cond_field_size(const field_cnvrt_aux_t *mysql_info, ctc_conds *cond); -int ctc_fill_cond_field_data(ctc_handler_t m_tch, Item *items, Field *mysql_field, - const field_cnvrt_aux_t *mysql_info, ctc_conds *cond); -int ctc_fill_cond_field_data_num(ctc_handler_t m_tch, Item *items, Field *mysql_field, - const field_cnvrt_aux_t *mysql_info, ctc_conds *cond); -int ctc_fill_cond_field_data_date(ctc_handler_t m_tch, const field_cnvrt_aux_t *mysql_info, - MYSQL_TIME ltime, date_detail_t *date_detail, ctc_conds *cond); -int ctc_fill_cond_field_data_string(ctc_handler_t m_tch, Item_func *item_func, ctc_conds *cond, bool no_backslash); -void update_value_by_charset(char *data, uint16 *size, uint16 bytes); -ctc_func_type_t item_func_to_ctc_func(Item_func::Functype fc); -int16_t ctc_get_column_by_field(Field **field, const char *col_name); +int dfs_fill_conds(ctc_handler_t m_tch, Item *items, Field **field, ctc_conds *conds, bool no_backslash, + en_ctc_func_type_t *functype); int ctc_get_column_cs(const CHARSET_INFO *cs); void cm_assert(bool condition); @@ -89,7 +132,21 @@ longlong get_session_variable_int_value_with_range(THD *thd, string sql_without_plaintext_password(ctc_ddl_broadcast_request* broadcast_req); string ctc_escape_single_quotation_str(string &src); string cnvrt_name_for_sql(string name); - + +typedef bool (*ctc_cond_is_support_t) (Item *term, Item_func::Functype parent_type); +typedef void (*ctc_cond_push_t) (Item *term, Item *&pushed_cond, Item *&remainder_cond); +typedef int (*ctc_cond_fill_t) (Item *item, ctc_conds *cond, Field **field, ctc_handler_t m_tch, + ctc_cond_list *list, bool no_backslash, en_ctc_func_type_t *functype); + +typedef struct en_ctc_cond_push_map { + Item::Type type; + ctc_cond_is_support_t is_support; + ctc_cond_push_t push; + ctc_cond_fill_t fill; +} ctc_cond_push_map; + +void cond_push_term(Item *term, Item *&pushed_cond, Item *&remainder_cond, Item_func::Functype parent_type); + #pragma GCC visibility pop #endif // __CTC_UTIL_H__ \ No newline at end of file diff --git a/storage/ctc/datatype_cnvrt_4_index_search.cc b/storage/ctc/datatype_cnvrt_4_index_search.cc index 9fc1492..9308135 100644 --- a/storage/ctc/datatype_cnvrt_4_index_search.cc +++ b/storage/ctc/datatype_cnvrt_4_index_search.cc @@ -72,27 +72,6 @@ static void ctc_convert_mysql_key_to_cantian(KEY_PART_INFO &key_part, const uint return; } -static void ctc_index_make_up_key_length(int *key, uint8_t **origin_key, uint32_t *origin_key_len, uint32_t length) { - int tmp_key = 0; - uint8_t *tmp_key_ptr = (uint8_t *)&tmp_key; - memcpy(tmp_key_ptr, *origin_key, *origin_key_len); - - // 通过符号位补齐高位字段 - if ((*origin_key_len == 1 && (tmp_key & 0x80)) || // 1表示MYSQL_TYPE_TINY类型,0x80用于获取origin_key的符号位 - (*origin_key_len == 2 && (tmp_key & 0x8000)) || // 2表示MYSQL_TYPE_SHORT类型,0x8000用于获取origin_key的符号位 - (*origin_key_len == 3 && (tmp_key & 0x800000))) { // 3表示MMYSQL_TYPE_INT24类型,0x800000用于获取origin_key的符号位 - *key = 0xFFFFFFFF; // 将key的bit位全赋值为1 - } else { - *key = 0; - } - - memcpy(key, *origin_key, *origin_key_len); - *origin_key = reinterpret_cast(key); - *origin_key_len = length; - - return; -} - int ctc_fill_index_key_info(TABLE *table, const uchar *key, uint key_len, const key_range *end_range, index_key_info_t *index_key_info, bool index_skip_scan) { const uchar *my_key = nullptr; @@ -145,8 +124,13 @@ int ctc_convert_key_from_mysql_to_cantian(Field *field, uint8_t **mysql_ptr, dec // 针对tiny和short类型,对应到cantian是int类型,所以key length需要按照cantian大小的存储 if (mysql_info->mysql_field_type == MYSQL_TYPE_TINY || mysql_info->mysql_field_type == MYSQL_TYPE_SHORT || mysql_info->mysql_field_type == MYSQL_TYPE_INT24) { - ctc_index_make_up_key_length(reinterpret_cast(cantian_ptr), mysql_ptr, len, sizeof(int)); - + if (convert_numeric_to_cantian(mysql_info, reinterpret_cast(*mysql_ptr), + reinterpret_cast(cantian_ptr), field, len) != CT_SUCCESS) { + ctc_log_error("convert_numeric_to_cantian: convert mysql index search key failed"); + return CT_ERROR; + } + *mysql_ptr = reinterpret_cast(cantian_ptr); + *len = sizeof(int32_t); return ret; } @@ -180,7 +164,9 @@ int ctc_convert_key_from_mysql_to_cantian(Field *field, uint8_t **mysql_ptr, dec } if (field->type() == MYSQL_TYPE_DECIMAL || field->type() == MYSQL_TYPE_NEWDECIMAL) { - ret = decimal_mysql_to_cantian(*mysql_ptr, reinterpret_cast(cantian_ptr), field, len); + Field_new_decimal *f = dynamic_cast(field); + CTC_RET_ERR_IF_NULL(f); + ret = decimal_mysql_to_cantian(*mysql_ptr, reinterpret_cast(cantian_ptr), f->precision, f->dec, len); if (ret != CT_SUCCESS) { ctc_log_error("ctc convert index decimal to cantian failed."); return ret; diff --git a/storage/ctc/datatype_cnvrtr.cc b/storage/ctc/datatype_cnvrtr.cc index ecd12e9..13300d3 100644 --- a/storage/ctc/datatype_cnvrtr.cc +++ b/storage/ctc/datatype_cnvrtr.cc @@ -27,6 +27,8 @@ #include "ctc_log.h" #include "decimal_convert.h" #include "ctc_srv.h" +#include "mysql/plugin.h" + #ifdef FEATURE_X_FOR_MYSQL_26 #include "sql/json_dom.h" #elif defined(FEATURE_X_FOR_MYSQL_32) @@ -450,12 +452,16 @@ void convert_digital_to_dec4(dec4_t *d4, uint8 *digits, bool sign, int start, in cell_idx++; } // remaining numbers - while (digidx <= end) { + int non_zero_end = end; + while (non_zero_end >= 0 && digits[non_zero_end] == 0) { + non_zero_end--; + } + while (digidx <= non_zero_end) { d4->cells[cell_idx] = 0; - if (digidx + DIG_PER_DEC4 <= end) { + if (digidx + DIG_PER_DEC4 <= non_zero_end) { d4->cells[cell_idx] = restore_digital(digits, digidx, digidx + DIG_PER_DEC4 - 1, DIG_PER_DEC4); } else { - d4->cells[cell_idx] = restore_digital(digits, digidx, end, DIG_PER_DEC4); + d4->cells[cell_idx] = restore_digital(digits, digidx, non_zero_end, DIG_PER_DEC4); } digidx += DIG_PER_DEC4; cell_idx++; @@ -487,6 +493,9 @@ void convert_dec4_to_digital(dec4_t *dec4, uint8 *digits, int &start, int &point j++; } end = i * DIG_PER_DEC4 - 1; // the last number index + if (dec4->expn > dec4->ncells - 1) { // corresponding format:d * 10^x + end = point; + } // remove leading zero while (end >= point && digits[end] == 0) { end--; @@ -553,13 +562,9 @@ void convert_dec4_to_mydec(dec4_t *from, my_decimal *to) decimal(prec,scale):prec indicates the maximum number of significant digits, scale indicates the maximum number of decimal places that can be stored. */ -int decimal_mysql_to_cantian(const uint8_t *mysql_ptr, uchar *cantian_ptr, Field *mysql_field, uint32 *length) +int decimal_mysql_to_cantian(const uint8_t *mysql_ptr, uchar *cantian_ptr, const int prec, const int scale, uint32 *length) { int ret = 0; - const int scale = mysql_field->decimals(); - Field_new_decimal *f = dynamic_cast(mysql_field); - CTC_RET_ERR_IF_NULL(f); - const int prec = f->precision; my_decimal d; ret = binary2my_decimal(E_DEC_FATAL_ERROR, mysql_ptr, &d, prec, scale); if (ret != E_DEC_OK) { @@ -914,27 +919,36 @@ void bit_cnvt_cantian_mysql(const uchar *cantian_ptr, uchar *mysql_ptr, Field *m return; } } +template +void convert_numeric_datatype(uchar *target_ptr, const uchar *source_ptr, bool is_unsigned) { + if (is_unsigned) { + *(U *)target_ptr = static_cast(*(const SU *)source_ptr); + } else { + *(T *)target_ptr = *(const S *)source_ptr; + } +} -/** - @brief - convert numeric data from mysql to cantian -*/ int convert_numeric_to_cantian(const field_cnvrt_aux_t *mysql_info, const uchar *mysql_ptr, uchar *cantian_ptr, - Field *mysql_field, uint32_t *length) + Field *mysql_field, uint32_t *length) { int res = 0; + bool is_unsigned = mysql_field->is_unsigned(); switch (mysql_info->mysql_field_type) { case MYSQL_TYPE_TINY: - *(int32_t *)cantian_ptr = *(const int8_t *)mysql_ptr; + convert_numeric_datatype(cantian_ptr, mysql_ptr, is_unsigned); break; case MYSQL_TYPE_SHORT: - *(int32_t *)cantian_ptr = *(const int16_t *)mysql_ptr; + convert_numeric_datatype(cantian_ptr, mysql_ptr, is_unsigned); break; case MYSQL_TYPE_INT24: - *(int32_t *)cantian_ptr = sint3korr(mysql_ptr); + if (is_unsigned) { + *(uint32_t *)cantian_ptr = uint3korr(mysql_ptr); + } else { + *(int32_t *)cantian_ptr = sint3korr(mysql_ptr); + } break; case MYSQL_TYPE_LONG: - *(int32_t *)cantian_ptr = *(const int32_t *)mysql_ptr; + convert_numeric_datatype(cantian_ptr, mysql_ptr, is_unsigned); break; case MYSQL_TYPE_FLOAT: *(double *)cantian_ptr = *(const float *)mysql_ptr; @@ -946,11 +960,14 @@ int convert_numeric_to_cantian(const field_cnvrt_aux_t *mysql_info, const uchar *(uint64_t *)cantian_ptr = (uint64_t)bit_cnvt_mysql_cantian(mysql_ptr, mysql_field); break; case MYSQL_TYPE_LONGLONG: - *(int64_t *)cantian_ptr = *(const int64_t *)mysql_ptr; - break; - case MYSQL_TYPE_NEWDECIMAL: - res = decimal_mysql_to_cantian(mysql_ptr, cantian_ptr, mysql_field, length); + convert_numeric_datatype(cantian_ptr, mysql_ptr, is_unsigned); break; + case MYSQL_TYPE_NEWDECIMAL: { + Field_new_decimal *f = dynamic_cast(mysql_field); + CTC_RET_ERR_IF_NULL(f); + res = decimal_mysql_to_cantian(mysql_ptr, cantian_ptr, f->precision, f->dec, length); + break; + } default: ctc_log_error("[mysql2cantian]unsupport numeric datatype %d", mysql_info->mysql_field_type); assert(0); @@ -1240,36 +1257,37 @@ int convert_datetime_to_cantian(const field_cnvrt_aux_t* mysql_info, uchar *cant convert numeric data from cantian to mysql */ static void convert_numeric_to_mysql(const field_cnvrt_aux_t *mysql_info, uchar *mysql_ptr, - uchar *cantian_ptr, Field *mysql_field) + const uchar *cantian_ptr, Field *mysql_field) { + bool is_unsigned = mysql_field->is_unsigned(); switch (mysql_info->mysql_field_type) { case MYSQL_TYPE_TINY: - *(int8_t *)mysql_ptr = *(int32_t *)cantian_ptr; + convert_numeric_datatype(mysql_ptr, cantian_ptr, is_unsigned); break; case MYSQL_TYPE_SHORT: - *(int16_t *)mysql_ptr = *(int32_t *)cantian_ptr; + convert_numeric_datatype(mysql_ptr, cantian_ptr, is_unsigned); break; case MYSQL_TYPE_INT24: // MEDIUMINT is 3 bytes at mysql side, get 3 bytes data from cantian_ptr memcpy(mysql_ptr, cantian_ptr, 3 * sizeof(char)); break; case MYSQL_TYPE_LONG: - *(int32_t *)mysql_ptr = *(int32_t *)cantian_ptr; + convert_numeric_datatype(mysql_ptr, cantian_ptr, is_unsigned); break; case MYSQL_TYPE_FLOAT: - *(float *)mysql_ptr = *(double *)cantian_ptr; + *(float *)mysql_ptr = *(const double *)cantian_ptr; break; case MYSQL_TYPE_DOUBLE: - *(double *)mysql_ptr = *(double *)cantian_ptr; + *(double *)mysql_ptr = *(const double *)cantian_ptr; break; case MYSQL_TYPE_BIT: bit_cnvt_cantian_mysql(cantian_ptr, mysql_ptr, mysql_field); break; case MYSQL_TYPE_LONGLONG: - *(int64_t *)mysql_ptr = *(int64_t *)cantian_ptr; + convert_numeric_datatype(mysql_ptr, cantian_ptr, is_unsigned); break; case MYSQL_TYPE_NEWDECIMAL: - decimal_cantian_to_mysql(mysql_ptr, cantian_ptr, mysql_field); + decimal_cantian_to_mysql(mysql_ptr, const_cast(cantian_ptr), mysql_field); break; default: ctc_log_error("[cantian2mysql]unsupport numeric datatype %d", mysql_info->mysql_field_type); @@ -1755,19 +1773,49 @@ int mysql_record_to_cantian_record(const TABLE &table, record_buf_info_t *record return 0; } +void generate_mysql_record_row_desc(const TABLE &table, ulong *ncols, ulong *row_len, + ulong *offsets, ulong *null_bit_mask, ulong *null_bit_offsets, + MY_BITMAP *read_set) +{ + UNUSED_PARAM(read_set); + *ncols = 0; + // read_set optimize OFF route or mysql side don't provide read_set + *ncols = table.s->fields; + + for (uint column_id = 0; column_id < *ncols; column_id++) { + Field *field = table.field[column_id]; + offsets[column_id] = field->offset(table.record[0]); + + if (field->pack_length() + field->offset(table.record[0]) > *row_len) { + *row_len = field->pack_length() + field->offset(table.record[0]); + } + + if (field->is_nullable()) { + null_bit_mask[column_id] = field->null_bit; + null_bit_offsets[column_id] = field->null_offset(); + } else { + null_bit_mask[column_id] = 0; + null_bit_offsets[column_id] = 0; + } + } +} + void copy_column_data_to_mysql(field_info_t *field_info, const field_cnvrt_aux_t* mysql_info, ctc_handler_t &tch, bool is_index_only) { if (!bitmap_is_set(field_info->field->table->read_set, field_info->field->field_index()) && tch.sql_command == SQLCOM_SELECT) { - return; + ha_ctc *const ctc_handler = dynamic_cast(field_info->field->table->file); + if (!ctc_handler->m_ror_intersect) { + return; + } } uchar *src = NULL; uint16_t src_len = 0; switch (mysql_info->sql_data_type) { case NUMERIC_DATA: convert_numeric_to_mysql( - mysql_info, field_info->mysql_cur_field, field_info->cantian_cur_field, field_info->field); + mysql_info, field_info->mysql_cur_field, (const uchar *)field_info->cantian_cur_field, field_info->field); break; case DATETIME_DATA: convert_datetime_to_mysql( diff --git a/storage/ctc/datatype_cnvrtr.h b/storage/ctc/datatype_cnvrtr.h index fe0fbe1..dc41b3a 100644 --- a/storage/ctc/datatype_cnvrtr.h +++ b/storage/ctc/datatype_cnvrtr.h @@ -220,6 +220,8 @@ void cantian_record_to_mysql_record(const TABLE &table, index_info_t *index, rec int mysql_record_to_cantian_record(const TABLE &table, record_buf_info_t *record_buf, ctc_handler_t &tch, uint16_t *serial_column_offset, std::vector *fields=nullptr); +void generate_mysql_record_row_desc(const TABLE &table, ulong *ncols, ulong *row_len, ulong *offsets, + ulong *null_bit_mask, ulong *null_bit_offsets, MY_BITMAP *read_set); void cal_gcol_cnts_for_update(Field **field, uint column_id, uint32_t *virtual_gcol_cnt); void cantian_index_record_to_mysql_record(const TABLE &table, index_info_t *index, record_buf_info_t *record_buf, ctc_handler_t &tch, record_info_t *record_info); @@ -237,7 +239,7 @@ void decode_mysql_datetime(MYSQL_TIME& ltime, const field_cnvrt_aux_t* mysql_inf int convert_datetime_to_cantian(const field_cnvrt_aux_t* mysql_info , uchar *cantian_ptr, const uchar *mysql_ptr, Field *mysql_field); -int decimal_mysql_to_cantian(const uint8_t *mysql_ptr, uchar *cantian_ptr, Field *mysql_field, uint32 *length); +int decimal_mysql_to_cantian(const uint8_t *mysql_ptr, uchar *cantian_ptr, const int prec, const int scale, uint32 *length); int convert_numeric_to_cantian(const field_cnvrt_aux_t *mysql_info, const uchar *mysql_ptr, uchar *cantian_ptr, Field *mysql_field, uint32_t *length); void cm_encode_date(const date_detail_t *detail, date_t *date); diff --git a/storage/ctc/ha_ctc.cc b/storage/ctc/ha_ctc.cc index 2b07df8..3dd320b 100644 --- a/storage/ctc/ha_ctc.cc +++ b/storage/ctc/ha_ctc.cc @@ -72,11 +72,12 @@ Happy coding!
-Brian */ - +#include "my_systime.h" +#include "my_time.h" #include "ha_ctc.h" #include "ha_ctc_ddl.h" #include "ha_ctcpart.h" - +#include "ha_ctc_pq.h" #include #include #include @@ -142,6 +143,11 @@ * SYSTEM VARIABLES CAN BE DISPLAYED AS: * mysql> SHOW GLOBAL VARIABLES like'%ctc%' */ +#define CTC_MAX_SAMPLE_SIZE (4096) // MB +#define CTC_MIN_SAMPLE_SIZE (32) // MB +#define CTC_DEFAULT_SAMPLE_SIZE (128) // MB + +bool enable_stat = true; static void ctc_statistics_enabled_update(THD * thd, SYS_VAR *, void *var_ptr, const void *save) { bool enabled = *static_cast(var_ptr) = *static_cast(save); @@ -175,8 +181,8 @@ int32_t ctc_metadata_normalization = (int32_t)metadata_switchs::DEFAULT; static MYSQL_SYSVAR_INT(metadata_normalization, ctc_metadata_normalization, PLUGIN_VAR_READONLY, "Option for Mysql-Cantian metadata normalization.", nullptr, nullptr, -1, -1, 3, 0); -static mutex m_ctc_cluster_role_mutex; -int32_t ctc_cluster_role = (int32_t)dis_cluster_role::DEFAULT; +extern int32_t ctc_cluster_role; +extern mutex m_ctc_cluster_role_mutex; static MYSQL_SYSVAR_INT(cluster_role, ctc_cluster_role, PLUGIN_VAR_READONLY, "flag for Disaster Recovery Cluster Role.", nullptr, nullptr, -1, -1, 2, 0); @@ -240,14 +246,79 @@ static MYSQL_SYSVAR_UINT(update_analyze_time, ctc_update_analyze_time, PLUGIN_VA "CBO updating time by CTC. Unit is second.", nullptr, nullptr, CTC_ANALYZE_TIME_SEC, 0, 900, 0); +static mutex m_ctc_sample_size_mutex; +uint32_t ctc_sample_size; +static int check_sample_size(THD *, SYS_VAR *, void *save, struct st_mysql_value *value) +{ + longlong in_val; + value->val_int(value, &in_val); + + if (in_val < CTC_MIN_SAMPLE_SIZE || in_val >= CTC_MAX_SAMPLE_SIZE) { + std::stringstream error_str; + error_str << "The value " << in_val + << " is not within the range of accepted values for the option " + << "ctc_sample_size.The value must be between " + << CTC_MIN_SAMPLE_SIZE << " inclusive and " + << CTC_MAX_SAMPLE_SIZE << " exclusive."; + my_message(ER_WRONG_VALUE_FOR_VAR, error_str.str().c_str(), MYF(0)); + + return CT_ERROR; + } + + *(longlong *)save = in_val; + + return CT_SUCCESS; +} + +static void update_sample_size(THD *thd, SYS_VAR *, void *, const void *save) +{ + lock_guard lock(m_ctc_sample_size_mutex); + List_iterator_fast var_it(thd->lex->var_list); + var_it.rewind(); + set_var_base *var = nullptr; + string name_str; + while((var = var_it++)) { + if (typeid(*var) == typeid(set_var)) { + set_var *setvar = dynamic_cast(var); +#ifdef FEATURE_X_FOR_MYSQL_32 + name_str = setvar->m_var_tracker.get_var_name(); +#elif defined(FEATURE_X_FOR_MYSQL_26) + name_str = setvar->var->name.str; +#endif + if (name_str != "ctc_sample_size") { + continue; + } + bool need_persist = (setvar->type == OPT_PERSIST); + if (ctc_update_sample_size(*static_cast(save), need_persist) == CT_SUCCESS) { + ctc_sample_size = *static_cast(save); + } + } + } +} + +static MYSQL_SYSVAR_UINT(sample_size, ctc_sample_size, PLUGIN_VAR_RQCMDARG, + "The size of the statistical sample data, measured in megabytes (MB).", + check_sample_size, update_sample_size, + CTC_DEFAULT_SAMPLE_SIZE, CTC_MIN_SAMPLE_SIZE, CTC_MAX_SAMPLE_SIZE, 0); + bool ctc_select_prefetch = true; static MYSQL_SYSVAR_BOOL(select_prefetch, ctc_select_prefetch, PLUGIN_VAR_RQCMDARG, "Indicates whether using prefetch in select.", nullptr, nullptr, true); +int32_t parallel_read_threads = 4; +static MYSQL_THDVAR_INT(parallel_read_threads, PLUGIN_VAR_OPCMDARG, + "Degree of Parallel for turbo plugin for a single table in single session", nullptr, nullptr, + 4, 1, CT_MAX_PARAL_QUERY, 0); + +int32_t ctc_parallel_max_read_threads = 128; +static MYSQL_SYSVAR_INT(parallel_max_read_threads, ctc_parallel_max_read_threads, PLUGIN_VAR_OPCMDARG, + "Global Degree of Parallel for turbo plugin", nullptr, nullptr, 128, 1, CT_MAX_PARAL_QUERY, 0); + // All global and session system variables must be published to mysqld before // use. This is done by constructing a NULL-terminated array of the variables // and linking to it in the plugin public interface. static SYS_VAR *ctc_system_variables[] = { + MYSQL_SYSVAR(sample_size), MYSQL_SYSVAR(lock_wait_timeout), MYSQL_SYSVAR(instance_id), MYSQL_SYSVAR(sampling_ratio), @@ -265,6 +336,8 @@ static SYS_VAR *ctc_system_variables[] = { MYSQL_SYSVAR(update_analyze_time), MYSQL_SYSVAR(stats_auto_recalc), MYSQL_SYSVAR(select_prefetch), + MYSQL_SYSVAR(parallel_read_threads), + MYSQL_SYSVAR(parallel_max_read_threads), nullptr }; @@ -521,290 +594,11 @@ static bool is_lock_table(MYSQL_THD thd) { return false; } -static bool check_cmp_result(Item *term) { - Item_func *item_func = dynamic_cast(term); - if (item_func == nullptr) { - return false; - } - - Item_field *item_field = dynamic_cast(item_func->arguments()[0]); - Item_result cmp_context_next = item_func->arguments()[1]->cmp_context; - if (item_field == nullptr) { - return false; - } - - Item::Type type = item_func->arguments()[1]->type(); - - if (type == Item::NULL_ITEM) { - return true; - } - if (item_field->data_type() == MYSQL_TYPE_YEAR) { - return type == Item::INT_ITEM && cmp_context_next == INT_RESULT; - } - - if (is_temporal_type(item_field->data_type())) { - if (!((item_func->arguments()[1])->basic_const_item() && cmp_context_next == INT_RESULT)) { - return false; - } - if (item_field->data_type() == MYSQL_TYPE_TIMESTAMP) { - MYSQL_TIME ltime; - Item_func_comparison *item_func_comparison = dynamic_cast(term); - if (item_func_comparison == nullptr) { - return false; - } - - Item_func *item_date_func = dynamic_cast(item_func->arguments()[1]); - if (item_date_func == nullptr) { - return false; - } - Item_date_literal *item_date_literal = (Item_date_literal *)(item_date_func); - if (item_date_literal == nullptr) { - return false; - } - if (item_date_literal->get_date(<ime, TIME_FUZZY_DATE)) { - return false; - } - if (non_zero_date(ltime)) { - return ltime.year && ltime.month && ltime.day; - } - } - return true; - } - - if (is_string_type(item_field->data_type())) { - return type == Item::STRING_ITEM && cmp_context_next == STRING_RESULT; - } - - if (is_integer_type(item_field->data_type())) { - return (type == Item::INT_ITEM && cmp_context_next == INT_RESULT) || type == Item::CACHE_ITEM; - } - - if (is_numeric_type(item_field->data_type())) { - return (type == Item::REAL_ITEM || type == Item::DECIMAL_ITEM) && cmp_context_next != STRING_RESULT; - } - - return false; -} - -static bool is_supported_datatype_cond(enum_field_types datatype) { - switch (datatype) { - case MYSQL_TYPE_JSON: - case MYSQL_TYPE_ENUM: - case MYSQL_TYPE_SET: - case MYSQL_TYPE_BIT: - case MYSQL_TYPE_NULL: - case MYSQL_TYPE_TYPED_ARRAY: - case MYSQL_TYPE_TINY_BLOB: - case MYSQL_TYPE_MEDIUM_BLOB: - case MYSQL_TYPE_LONG_BLOB: - case MYSQL_TYPE_BLOB: { - return false; - } - default: - return true; - } -} - -static bool is_supported_func_item(Item *term) { - Item_func *item_func = dynamic_cast(term); - if (item_func == nullptr) { - return false; - } - Item_func::Functype functype = item_func->functype(); - // filter unspported func - if (functype != Item_func::EQ_FUNC && - functype != Item_func::EQUAL_FUNC && - functype != Item_func::NE_FUNC && - functype != Item_func::LT_FUNC && - functype != Item_func::LE_FUNC && - functype != Item_func::GE_FUNC && - functype != Item_func::GT_FUNC && - functype != Item_func::LIKE_FUNC && - functype != Item_func::ISNULL_FUNC && - functype != Item_func::ISNOTNULL_FUNC) { - return false; - } - - Item::Type type = (item_func->arguments()[0])->type(); - // filter expressions - if (type != Item::FIELD_ITEM) { - return false; - } - - Item_field *item_field = dynamic_cast(item_func->arguments()[0]); - if (item_field == nullptr) { - return false; - } - - // filter generated column - if (item_field->field->is_gcol() || !item_field->field->part_of_prefixkey.is_clear_all()) { - return false; - } - - // filter unsupport datatype - if (!is_supported_datatype_cond(item_field->field->real_type())) { - return false; - } - - // filter binary - if (item_field->data_type() == MYSQL_TYPE_STRING) { - if (item_field->collation.collation->pad_char == '\0') { - return false; - } - } - - if (functype == Item_func::ISNULL_FUNC || functype == Item_func::ISNOTNULL_FUNC) { - return true; - } - - if (functype == Item_func::LIKE_FUNC) { - Item_func_like *like_func = dynamic_cast(item_func); - if (like_func == nullptr || like_func->escape_was_used_in_parsing() || !is_string_type(item_field->data_type())) { - return false; - } - } - - if (item_field->cmp_context == INVALID_RESULT) { - return false; - } - - return check_cmp_result(term); -} - -int create_and_conditions(Item_cond *cond, List pushed_list, - List remainder_list, Item *&pushed_cond, - Item *&remainder_cond) { - if (remainder_list.is_empty()) { - // Entire cond pushed, no remainder - pushed_cond = cond; - remainder_cond = nullptr; - return 0; - } - if (pushed_list.is_empty()) { - // Nothing pushed, entire 'cond' is remainder - pushed_cond = nullptr; - remainder_cond = cond; - return 0; - } - - // Condition was partly pushed, with some remainder - if (pushed_list.elements == 1) { - // Single boolean term pushed, return it - pushed_cond = pushed_list.head(); - } else { - // Construct an AND'ed condition of pushed boolean terms - pushed_cond = new Item_cond_and(pushed_list); - if (pushed_cond == nullptr) { - return 1; - } - } - - if (remainder_list.elements == 1) { - // A single boolean term as remainder, return it - remainder_cond = remainder_list.head(); - } else { - // Construct a remainder as an AND'ed condition of the boolean terms - remainder_cond = new Item_cond_and(remainder_list); - if (remainder_cond == nullptr) { - return 1; - } - } - return 0; -} - -int create_or_conditions(Item_cond *cond, List pushed_list, - List remainder_list, Item *&pushed_cond, - Item *&remainder_cond) { - assert(pushed_list.elements == cond->argument_list()->elements); - - if (remainder_list.is_empty()) { - // Entire cond pushed, no remainder - pushed_cond = cond; - remainder_cond = nullptr; - } else { - // When condition was partially pushed, we need to reevaluate - // original OR-cond on the server side: - remainder_cond = cond; - - // Construct an OR condition of pushed terms - pushed_cond = new Item_cond_or(pushed_list); - if (pushed_cond == nullptr){ - return 1; - } - } - return 0; -} - -void cond_push_boolean_term(Item *term, Item *&pushed_cond, Item *&remainder_cond) { - if (term->type() == Item::COND_ITEM) { - List pushed_list; - List remainder_list; - Item_cond *cond = dynamic_cast(term); - if (cond == nullptr) { - return; - } - if (cond->functype() == Item_func::COND_AND_FUNC) { - List_iterator li(*cond->argument_list()); - Item *boolean_term; - while ((boolean_term = li++)) { - Item *pushed = nullptr, *remainder = nullptr; - cond_push_boolean_term(boolean_term, pushed, remainder); - if (pushed != nullptr) pushed_list.push_back(pushed); - if (remainder != nullptr) remainder_list.push_back(remainder); - } - - if (create_and_conditions(cond, pushed_list, remainder_list, pushed_cond, remainder_cond)) { - pushed_cond = nullptr; - remainder_cond = cond; - return; - } - } else { - assert(cond->functype() == Item_func::COND_OR_FUNC); - List_iterator li(*cond->argument_list()); - Item *boolean_term; - while ((boolean_term = li++)) { - Item *pushed = nullptr, *remainder = nullptr; - cond_push_boolean_term(boolean_term, pushed, remainder); - if (pushed == nullptr) { - // Failure of pushing one of the OR-terms fails entire OR'ed cond - pushed_cond = nullptr; - remainder_cond = cond; - return; - } - - if (pushed != nullptr) pushed_list.push_back(pushed); - if (remainder != nullptr) remainder_list.push_back(remainder); - } - - if (create_or_conditions(cond, pushed_list, remainder_list, pushed_cond, - remainder_cond)) { - // Failed, discard pushed conditions. - pushed_cond = nullptr; - remainder_cond = cond; - return; - } - } - } else if (term->type() == Item::FUNC_ITEM) { - if (is_supported_func_item(term)) { - pushed_cond = term; - remainder_cond = nullptr; - return; - } - pushed_cond = nullptr; - remainder_cond = term; - return; - } else { - pushed_cond = nullptr; - remainder_cond = term; - return; - } -} - void ha_ctc::prep_cond_push(const Item *cond) { Item *item = const_cast(cond); Item *pushed_cond = nullptr; Item *remainder = nullptr; - cond_push_boolean_term(item, pushed_cond, remainder); + cond_push_term(item, pushed_cond, remainder, Item_func::COND_AND_FUNC); m_pushed_conds = pushed_cond; m_remainder_conds = remainder; } @@ -1538,7 +1332,9 @@ static int ctc_start_trx_and_assign_scn( uint32_t lock_wait_timeout = THDVAR(thd, lock_wait_timeout); ctc_trx_context_t trx_context = {isolation_level, autocommit, lock_wait_timeout, false}; bool is_mysql_local = (sess_ctx->set_flag & CTC_DDL_LOCAL_ENABLED); - ct_errno_t ret = (ct_errno_t)ctc_trx_begin(&tch, trx_context, is_mysql_local); + struct timeval begin_time; + gettimeofday(&begin_time, NULL); + ct_errno_t ret = (ct_errno_t)ctc_trx_begin(&tch, trx_context, is_mysql_local, begin_time, &enable_stat); update_sess_ctx_by_tch(tch, hton, thd); if (ret != CT_SUCCESS) { ctc_log_error("start trx failed with error code: %d", ret); @@ -1645,20 +1441,18 @@ static typename std::enable_if::type // no action here } -template -static typename std::enable_if::type -attachable_trx_update_pre_addr(T *ctc_hton, THD *thd, ctc_handler_t *tch, bool set_to_pre_addr) { +#ifdef METADATA_NORMALIZED +static void attachable_trx_update_pre_addr(THD *thd, ctc_handler_t *tch, bool set_to_pre_addr) { if (thd->is_attachable_transaction_active() && (thd->tx_isolation == ISO_READ_UNCOMMITTED) - && (ctc_hton->pre_sess_addr != 0) && thd->query_plan.get_command() == SQLCOM_RENAME_TABLE) { - tch->pre_sess_addr = set_to_pre_addr ? ctc_hton->pre_sess_addr : 0; + && (thd->pre_sess_addr != 0) && thd->query_plan.get_command() == SQLCOM_RENAME_TABLE) { + tch->pre_sess_addr = set_to_pre_addr ? thd->pre_sess_addr : 0; } } - -template -static typename std::enable_if::type -attachable_trx_update_pre_addr(T *ctc_hton MY_ATTRIBUTE((unused)), THD *thd MY_ATTRIBUTE((unused)), +#else +static void attachable_trx_update_pre_addr(THD *thd MY_ATTRIBUTE((unused)), ctc_handler_t *tch MY_ATTRIBUTE((unused)), bool set_to_pre_addr MY_ATTRIBUTE((unused))) { } +#endif static void ctc_free_cursors_no_autocommit(THD *thd, ctc_handler_t *tch, thd_sess_ctx_s *sess_ctx) { if (!thd->in_multi_stmt_transaction_mode()) { @@ -1684,6 +1478,19 @@ static void ctc_free_cursors_no_autocommit(THD *thd, ctc_handler_t *tch, thd_ses ctc_free_buf(tch, (uint8_t *)cursors); } +bool is_dml_sql_cmd(enum_sql_command sql_cmd) { + + if (sql_cmd == SQLCOM_SELECT || sql_cmd == SQLCOM_UPDATE || + sql_cmd == SQLCOM_INSERT || sql_cmd == SQLCOM_INSERT_SELECT || + sql_cmd == SQLCOM_DELETE || sql_cmd == SQLCOM_REPLACE || + sql_cmd == SQLCOM_REPLACE_SELECT || sql_cmd == SQLCOM_DO + ) { + return true; + } + + return false; +} + /** Commits a transaction in an ctc database or marks an SQL statement ended. @param: hton in, ctc handlerton @@ -1709,10 +1516,10 @@ static int ctc_commit(handlerton *hton, THD *thd, bool commit_trx) { ct_errno_t ret = CT_SUCCESS; thd_sess_ctx_s *sess_ctx = (thd_sess_ctx_s *)thd_get_ha_data(thd, hton); assert(sess_ctx != nullptr); - + bool is_dmlsql = is_dml_sql_cmd(thd->lex->sql_command); if (will_commit) { commit_preprocess(thd, &tch); - attachable_trx_update_pre_addr(ctc_hton, thd, &tch, true); + attachable_trx_update_pre_addr(thd, &tch, true); int32_t total_csize = sess_ctx->cursors_map->size(); if (sess_ctx->invalid_cursors != nullptr) { @@ -1724,7 +1531,11 @@ static int ctc_commit(handlerton *hton, THD *thd, bool commit_trx) { } assert((total_csize == 0) ^ (cursors != nullptr)); ctc_copy_cursors_to_free(sess_ctx, cursors, 0); - ret = (ct_errno_t)ctc_trx_commit(&tch, cursors, total_csize, &is_ddl_commit); + char sql_str[MAX_DML_SQL_LEN] = ""; + if (is_dmlsql && thd->query().str != NULL && thd->query().length > 0 && enable_stat) { + strncpy(sql_str, thd->query().str, MAX_DML_SQL_LEN - 1); + } + ret = (ct_errno_t)ctc_trx_commit(&tch, cursors, total_csize, &is_ddl_commit, sql_str); ctc_free_buf(&tch, (uint8_t *)cursors); if (ret != CT_SUCCESS) { ctc_log_error("commit atomic ddl failed with error code: %d", ret); @@ -1749,6 +1560,16 @@ static int ctc_commit(handlerton *hton, THD *thd, bool commit_trx) { } sess_ctx->is_ctc_trx_begin = 0; } else { + char sql_str[MAX_DML_SQL_LEN] = ""; + if (is_dmlsql && thd->query().str != NULL && thd->query().length > 0 && enable_stat) { + strncpy(sql_str, thd->query().str, MAX_DML_SQL_LEN - 1); + ret = (ct_errno_t)ctc_statistic_commit(&tch,sql_str); + if (ret != CT_SUCCESS) { + ctc_log_error("commit statistic failed with error code: %d", ret); + END_RECORD_STATS(EVENT_TYPE_COMMIT) + return convert_ctc_error_code_to_mysql(ret); + } + } ctc_free_cursors_no_autocommit(thd, &tch, sess_ctx); } @@ -1953,9 +1774,6 @@ static void ctc_lock_table_handle_error(int err_code, ctc_lock_table_info *lock_ break; default: - my_printf_error(err_code, "The table or database is being used. Please try again later.", MYF(0)); - ctc_log_error("[CTC_MDL_LOCK]: Lock failed, err=%d, lock_info=(%s, %s), sql=%s, conn_id=%u, ctc_instance_id=%u", - err_code, lock_info->db_name, lock_info->table_name, thd->query().str, tch.thd_id, tch.inst_id); break; } @@ -1985,6 +1803,8 @@ static int ctc_notify_pre_event(THD *thd, handlerton *ctc_hton, ctc_handler_t &t ctc_lock_table_handle_error(err_code, lock_info, tch, thd); return ret; } + ctc_log_system("[CTC_MDL_LOCK]: current node get another node lock success, err=%d, lock_info=(%s, %s), sql=%s, conn_id=%u, ctc_instance_id=%u", + err_code, lock_info->db_name, lock_info->table_name, thd->query().str, tch.thd_id, tch.inst_id); } switch (sql_command) { @@ -2991,6 +2811,20 @@ bool ha_ctc::is_record_buffer_wanted(ha_rows *const max_rows) const { return false; } +void ha_ctc::set_ror_intersect() { +#ifdef FEATURE_X_FOR_MYSQL_32 + if (table->reginfo.qep_tab && table->reginfo.qep_tab->access_path() && + table->reginfo.qep_tab->access_path()->type == AccessPath::ROWID_INTERSECTION) { + m_ror_intersect = true; + } +#elif defined(FEATURE_X_FOR_MYSQL_26) + if (table->reginfo.qep_tab && table->reginfo.qep_tab->quick() && + table->reginfo.qep_tab->quick()->get_type() == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT) { + m_ror_intersect = true; + } +#endif +} + // @ref set_record_buffer int ha_ctc::set_prefetch_buffer() { if (m_rec_buf) { @@ -3160,7 +2994,7 @@ int ctc_fill_conds(ctc_handler_t m_tch, const Item *pushed_cond, Field **field, ctc_conds *m_cond, bool no_backslash) { memset(m_cond, 0, sizeof(ctc_conds)); Item *items = const_cast(pushed_cond); - return dfs_fill_conds(m_tch, items, field, m_cond, no_backslash); + return dfs_fill_conds(m_tch, items, field, m_cond, no_backslash, NULL); } /** @@ -3189,6 +3023,7 @@ int ha_ctc::rnd_init(bool) { return 0; } + set_ror_intersect(); ct_errno_t ret = (ct_errno_t)set_prefetch_buffer(); if (ret != CT_SUCCESS) { END_RECORD_STATS(EVENT_TYPE_RND_INIT) @@ -3381,41 +3216,6 @@ EXTER_ATTACK int ha_ctc::rnd_pos(uchar *buf, uchar *pos) { return ret; } -double ha_ctc::scan_time() { - DBUG_TRACE; - double data_page_num = 1.0; - if (m_share && m_share->cbo_stats != nullptr) { - data_page_num = m_share->cbo_stats->ctc_cbo_stats_table->blocks; - } - return data_page_num; -} - -double ha_ctc::index_only_read_time(uint keynr, double records) { - double index_read_time; - uint32_t keys_per_block = (stats.block_size / 2 / - (table_share->key_info[keynr].key_length + ref_length) + 1); - index_read_time = ((double)(records + keys_per_block - 1) / (double)keys_per_block); - return index_read_time; -} - -double ha_ctc::read_time(uint index, uint ranges, ha_rows rows) { - DBUG_TRACE; - if (index != table->s->primary_key) { - return (handler::read_time(index, ranges, rows)); - } - - if (rows <= 2) { - return ((double)rows); - } - - double time_for_scan = scan_time(); - if (stats.records < rows) { - return (time_for_scan); - } - - return (ranges + (double)rows / (double)stats.records * time_for_scan); -} - /** @brief ::info() is used to return information to the optimizer. See my_base.h for @@ -3458,8 +3258,6 @@ double ha_ctc::read_time(uint index, uint ranges, ha_rows rows) { void ha_ctc::info_low() { if (m_share && m_share->cbo_stats != nullptr) { stats.records = m_share->cbo_stats->ctc_cbo_stats_table->estimate_rows; - stats.mean_rec_length = m_share->cbo_stats->ctc_cbo_stats_table->avg_row_len; - stats.block_size = m_share->cbo_stats->page_size; } } @@ -3662,6 +3460,7 @@ int ha_ctc::rnd_end() { int ha_ctc::index_init(uint index, bool sorted) { DBUG_TRACE; BEGIN_RECORD_STATS + set_ror_intersect(); ct_errno_t ret = (ct_errno_t)set_prefetch_buffer(); if (ret != CT_SUCCESS) { return ret; @@ -3699,6 +3498,11 @@ int ha_ctc::index_end() { return ret; } +int ha_ctc::cmp_ref(const uchar *ref1, const uchar *ref2) const { + DBUG_TRACE; + return ctc_cmp_cantian_rowid((const rowid_t *)ref1, (const rowid_t *)ref2); +} + int ha_ctc::process_cantian_record(uchar *buf, record_info_t *record_info, ct_errno_t ct_ret, int rc_ret) { int ret = CT_SUCCESS; check_error_code_to_mysql(ha_thd(), &ct_ret); @@ -3731,6 +3535,7 @@ EXTER_ATTACK int ha_ctc::index_read(uchar *buf, const uchar *key, uint key_len, reset_rec_buf(); } + m_is_covering_index = m_ror_intersect ? false : m_is_covering_index; m_action = m_is_covering_index ? EXP_CURSOR_ACTION_INDEX_ONLY : EXP_CURSOR_ACTION_SELECT; if (m_select_lock == lock_mode::EXCLUSIVE_LOCK) { enum_sql_command sql_command = (enum_sql_command)thd_sql_command(ha_thd()); @@ -3786,11 +3591,11 @@ EXTER_ATTACK int ha_ctc::index_read(uchar *buf, const uchar *key, uint key_len, update_member_tch(m_tch, ctc_hton, ha_thd()); record_info_t record_info = {m_read_buf, 0, nullptr, nullptr}; - attachable_trx_update_pre_addr(ctc_hton, ha_thd(), &m_tch, true); + attachable_trx_update_pre_addr(ha_thd(), &m_tch, true); ct_errno_t ct_ret = (ct_errno_t)ctc_index_read(&m_tch, &record_info, &index_key_info, get_select_mode(), m_cond, m_is_replace || m_is_insert_dup); update_sess_ctx_by_tch(m_tch, ctc_hton, ha_thd()); - attachable_trx_update_pre_addr(ctc_hton, ha_thd(), &m_tch, false); + attachable_trx_update_pre_addr(ha_thd(), &m_tch, false); if (index_key_info.need_init) { if (!(table_share->tmp_table != NO_TMP_TABLE && table_share->tmp_table != TRANSACTIONAL_TMP_TABLE)) { update_sess_ctx_cursor_by_tch(m_tch, ctc_hton, ha_thd()); @@ -3817,9 +3622,9 @@ int ha_ctc::index_fetch(uchar *buf) { ct_errno_t ct_ret = CT_SUCCESS; CTC_RETURN_IF_NOT_ZERO(ctc_alloc_ctc_buf_4_read()); record_info_t record_info = {m_read_buf, 0, nullptr, nullptr}; - attachable_trx_update_pre_addr(ctc_hton, ha_thd(), &m_tch, true); + attachable_trx_update_pre_addr(ha_thd(), &m_tch, true); ct_ret = (ct_errno_t)ctc_general_fetch(&m_tch, &record_info); - attachable_trx_update_pre_addr(ctc_hton, ha_thd(), &m_tch, false); + attachable_trx_update_pre_addr(ha_thd(), &m_tch, false); ret = process_cantian_record(buf, &record_info, ct_ret, HA_ERR_END_OF_FILE); END_RECORD_STATS(EVENT_TYPE_INDEX_FETCH) return ret; @@ -3849,9 +3654,9 @@ int ha_ctc::index_fetch(uchar *buf) { } } - attachable_trx_update_pre_addr(ctc_hton, ha_thd(), &m_tch, true); + attachable_trx_update_pre_addr(ha_thd(), &m_tch, true); mysql_ret = prefetch_and_fill_record_buffer(buf, ctc_general_prefetch); - attachable_trx_update_pre_addr(ctc_hton, ha_thd(), &m_tch, false); + attachable_trx_update_pre_addr(ha_thd(), &m_tch, false); if (mysql_ret != 0) { set_my_errno(mysql_ret); @@ -3901,6 +3706,8 @@ int ha_ctc::index_prev(uchar *buf) { int ha_ctc::index_first(uchar *buf) { DBUG_TRACE; ha_statistic_increment(&System_status_var::ha_read_first_count); + m_tch.cursor_addr = INVALID_VALUE64; + m_tch.cursor_valid = false; int error = index_read(buf, nullptr, 0, HA_READ_AFTER_KEY); /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */ if (error == HA_ERR_KEY_NOT_FOUND) { @@ -4227,9 +4034,31 @@ int ha_ctc::records_from_index(ha_rows *num_rows, uint inx) return ret; } +/** + * Retrieves and validates the statistics sample size system variable from Cantian. + * + * This function: + * 1. Gets the sample size value from Cantian engine via ctc_get_sample_size_value() + * 2. Validates that the value falls within acceptable range [CTC_MIN_SAMPLE_SIZE, CTC_MAX_SAMPLE_SIZE] + * 3. If valid, updates the global ctc_sample_size variable used for statistics sampling + * + * The sample size determines how much data is sampled when gathering table statistics. + * Invalid values are silently ignored, leaving ctc_sample_size unchanged. + */ +void ctc_get_sample_size_value() { + uint32_t sample_size = 0; + if (ctc_get_sample_size(&sample_size) == CT_SUCCESS) { + if (sample_size >= CTC_MIN_SAMPLE_SIZE && sample_size <= CTC_MAX_SAMPLE_SIZE) { + ctc_sample_size = sample_size; + } + } +} + int32_t ctc_get_cluster_role() { - if (ctc_cluster_role != (int32_t)dis_cluster_role::DEFAULT) { - return ctc_cluster_role; + /* Normally, the cluster type should only be PRIMARY or STANDBY */ + if (ctc_cluster_role == (int32_t)dis_cluster_role::PRIMARY || + ctc_cluster_role == (int32_t)dis_cluster_role::STANDBY) { + return ctc_cluster_role; } lock_guard lock(m_ctc_cluster_role_mutex); bool is_slave = false; @@ -4404,7 +4233,8 @@ int ha_ctc::external_lock(THD *thd, int lock_type) { */ int ha_ctc::start_stmt(THD *thd, thr_lock_type) { DBUG_TRACE; - + struct timeval begin_time; + gettimeofday(&begin_time, NULL); trans_register_ha(thd, false, ht, nullptr); // register trans to STMT update_member_tch(m_tch, ctc_hton, thd, false); @@ -4427,6 +4257,11 @@ int ha_ctc::start_stmt(THD *thd, thr_lock_type) { if (sess_ctx->is_ctc_trx_begin) { assert(m_tch.sess_addr != INVALID_VALUE64); assert(m_tch.thd_id == thd->thread_id()); + ct_errno_t ret = (ct_errno_t)ctc_statistic_begin(&m_tch,begin_time, &enable_stat); + if (ret != CT_SUCCESS) { + ctc_log_error("start statistic failed with error code: %d", ret); + return convert_ctc_error_code_to_mysql(ret); + } return 0; } @@ -4435,10 +4270,8 @@ int ha_ctc::start_stmt(THD *thd, thr_lock_type) { int isolation_level = isolation_level_to_cantian(thd_get_trx_isolation(thd)); ctc_trx_context_t trx_context = {isolation_level, autocommit, lock_wait_timeout, m_select_lock == lock_mode::EXCLUSIVE_LOCK}; - bool is_mysql_local = (sess_ctx->set_flag & CTC_DDL_LOCAL_ENABLED); - ct_errno_t ret = (ct_errno_t)ctc_trx_begin(&m_tch, trx_context, is_mysql_local); - + ct_errno_t ret = (ct_errno_t)ctc_trx_begin(&m_tch, trx_context, is_mysql_local, begin_time, &enable_stat); check_error_code_to_mysql(ha_thd(), &ret); update_sess_ctx_by_tch(m_tch, ctc_hton, thd); @@ -4599,34 +4432,6 @@ static bool ctc_show_status(handlerton *, THD *thd, stat_print_fn *stat_print, e return false; } -void ctc_set_mysql_read_only() { - ctc_log_system("[Disaster Recovecy] starting or initializing"); - super_read_only = true; - read_only = true; - opt_readonly = true; - ctc_log_system("[Disaster Recovery] set super_read_only = true."); -} - -void ctc_reset_mysql_read_only() { - ctc_log_system("[Disaster Recovecy] starting or initializing"); - super_read_only = false; - read_only = false; - opt_readonly = false; - ctc_log_system("[Disaster Recovery] set super_read_only = false."); -} - -int ctc_set_cluster_role_by_cantian(bool is_slave) { - lock_guard lock(m_ctc_cluster_role_mutex); - if (is_slave) { - ctc_cluster_role = (int32_t)dis_cluster_role::STANDBY; - ctc_set_mysql_read_only(); - } else { - ctc_cluster_role = (int32_t)dis_cluster_role::PRIMARY; - ctc_reset_mysql_read_only(); - } - return 0; -} - bool is_single_run_mode() { #ifndef WITH_CANTIAN @@ -4916,9 +4721,46 @@ static typename std::enable_if::type set_hton ctc_hton->binlog_log_query = ctc_binlog_log_query; } +#if FEATURE_FOR_EVERSQL +int ha_ctc_parallel_read_create_data_fetcher(parallel_read_create_data_fetcher_ctx_t &data_fetcher_ctx, + void *&data_fetcher) { + UNUSED_PARAM(data_fetcher_ctx); + UNUSED_PARAM(data_fetcher); + return 0; +} + +int ha_ctc_parallel_read_destory_data_fetcher(void *&data_fetcher) { + UNUSED_PARAM(data_fetcher); + return 0; +} + +int ha_ctc_parallel_read_start_data_fetch(parallel_read_start_data_fetch_ctx_t &start_data_fetch_ctx) { + UNUSED_PARAM(start_data_fetch_ctx); + return 0; +} + +int ha_ctc_parallel_read_init_data_fetcher(parallel_read_init_data_fetcher_ctx_t &init_data_fetcher_ctx) { + UNUSED_PARAM(init_data_fetcher_ctx); + return 0; +} + +int ha_ctc_parallel_read_add_target_to_data_fetcher( + parallel_read_add_target_to_data_fetcher_ctx_t &target_to_data_fetcher_ctx) { + UNUSED_PARAM(target_to_data_fetcher_ctx); + return 0; +} + +int ha_ctc_parallel_read_end_data_fetch(parallel_read_end_data_fetch_ctx_t &end_data_fetch_ctx) { + UNUSED_PARAM(end_data_fetch_ctx); + return 0; +} +#endif + extern int (*ctc_init)(); extern int (*ctc_deinit)(); +int ctc_push_to_engine(THD *thd, AccessPath *root_path, JOIN *); + static int ctc_init_func(void *p) { DBUG_TRACE; ctc_hton = (handlerton *)p; @@ -4958,6 +4800,16 @@ static int ctc_init_func(void *p) { #ifdef FEATURE_X_FOR_MYSQL_32 ctc_hton->push_to_engine = ctc_push_to_engine; #endif + +#ifdef FEATURE_X_FOR_EVERSQL + ctc_hton->data_fetcher_interface.parallel_read_create_data_fetcher = ha_ctc_parallel_read_create_data_fetcher; + ctc_hton->data_fetcher_interface.parallel_read_destory_data_fetcher = ha_ctc_parallel_read_destory_data_fetcher; + ctc_hton->data_fetcher_interface.parallel_read_start_data_fetch = ha_ctc_parallel_read_start_data_fetch; + ctc_hton->data_fetcher_interface.parallel_read_init_data_fetcher = ha_ctc_parallel_read_init_data_fetcher; + ctc_hton->data_fetcher_interface.parallel_read_add_target_to_data_fetcher = + ha_ctc_parallel_read_add_target_to_data_fetcher; + ctc_hton->data_fetcher_interface.parallel_read_end_data_fetch = ha_ctc_parallel_read_end_data_fetch; +#endif set_hton_members(ctc_hton); int ret = ctc_init(); if (ret != 0) { @@ -4985,6 +4837,9 @@ static int ctc_init_func(void *p) { return HA_ERR_INITIALIZATION; } ctc_get_cluster_role(); + + ctc_get_sample_size_value(); + ctc_log_system("[CTC_INIT]:SUCCESS!"); return 0; } @@ -5603,7 +5458,7 @@ int ha_ctc::initialize_cbo_stats() END_RECORD_STATS(EVENT_TYPE_INITIALIZE_DBO) return ERR_ALLOC_MEMORY; } - *m_share->cbo_stats = {0, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr, 0}; + *m_share->cbo_stats = {0, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr}; m_share->cbo_stats->ctc_cbo_stats_table = (ctc_cbo_stats_table_t*)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(ctc_cbo_stats_table_t), MYF(MY_WME)); if (m_share->cbo_stats->ctc_cbo_stats_table == nullptr) { @@ -5611,9 +5466,6 @@ int ha_ctc::initialize_cbo_stats() END_RECORD_STATS(EVENT_TYPE_INITIALIZE_DBO) return ERR_ALLOC_MEMORY; } - m_share->cbo_stats->ctc_cbo_stats_table->estimate_rows = 0; - m_share->cbo_stats->ctc_cbo_stats_table->avg_row_len = 0; - m_share->cbo_stats->ctc_cbo_stats_table->blocks = 0; m_share->cbo_stats->ctc_cbo_stats_table->columns = (ctc_cbo_stats_column_t*)my_malloc(PSI_NOT_INSTRUMENTED, table->s->fields * sizeof(ctc_cbo_stats_column_t), MYF(MY_WME)); if (m_share->cbo_stats->ctc_cbo_stats_table->columns == nullptr) { @@ -5970,7 +5822,7 @@ TABLE *ctc_get_basic_table(const AccessPath *path) { * * @return Possible ret code, '0' if no errors. */ -static int ctc_push_to_engine(THD *thd, AccessPath *root_path, JOIN *) { +int ctc_push_to_engine(THD *thd, AccessPath *root_path, JOIN *) { DBUG_TRACE; if (!thd->optimizer_switch_flag(OPTIMIZER_SWITCH_ENGINE_CONDITION_PUSHDOWN)) { diff --git a/storage/ctc/ha_ctc.h b/storage/ctc/ha_ctc.h index 3cd3482..d3e693a 100644 --- a/storage/ctc/ha_ctc.h +++ b/storage/ctc/ha_ctc.h @@ -22,7 +22,7 @@ #include #include - +#include "sql/tztime.h" #include "my_inttypes.h" #include "sql/handler.h" #include "sql/table.h" @@ -36,6 +36,7 @@ #include "sql/dd/types/schema.h" #include "sql/dd/types/object_table_definition.h" #include "sql/dd/string_type.h" +#include "sql/sql_optimizer.h" #include "clientbuild/include/mysql_version.h" #pragma GCC visibility push(default) @@ -65,6 +66,7 @@ using namespace std; #define DEFAULT_RANGE_DENSITY 0.5 #define PREFER_RANGE_DENSITY 0.8 #define CT_MAX_RECORD_LENGTH 64000 +#define INVALID_PART_ID (uint32)0xFFFFFFFF /* update if restraints changed in Cantian */ #define CTC_MAX_KEY_PART_LENGTH 4095 // CT_MAX_KEY_SIZE @@ -159,6 +161,73 @@ bool is_single_run_mode(); #endif #endif +#if !(FEATURE_FOR_EVERSQL) +// mock class specific for compiling EverSQL integration against MySQL +struct parallel_reader_data_frame_t { + /** caller should not care about the following members */ + uint64_t m_buf_size{0}; + uint32_t m_buf_id{0}; + /** caller can access the following members */ + char *m_buf{nullptr}; + + /** actual data size is zero: means the data + * has been read out completely. + */ + uint64_t m_actual_data_size{0}; + uint64_t m_buf_partition_id{0}; + + void init() + { + m_buf_size = 0; + m_buf_id = 0; + m_buf = nullptr; + m_actual_data_size = 0; + m_buf_partition_id = 0; + } +}; + +struct Parallel_reader_handler_config_t { + /** the desired, parallel background thread count to read table */ + uint32_t m_thread_count{4}; + /** the maximum data chunk size(bytes) which bk thread will + * fill with table data + */ + uint64_t m_buffer_size{0}; + /** the maximum row count per calling acquire table data */ + uint64_t m_row_num; +}; + +class ParallelReaderHandler { +public: + ParallelReaderHandler() = default; + ~ParallelReaderHandler() = default; + + struct mysql_row_desc_t { + ulong m_ncols{0}; + ulong m_row_len{0}; + const ulong *m_col_offsets{nullptr}; + const ulong *m_null_byte_offsets{nullptr}; + const ulong *m_null_bitmasks{nullptr}; + }; + + virtual mysql_row_desc_t get_row_info_for_parse() = 0; + virtual void reset_data_frame(parallel_reader_data_frame_t *data_frame) = 0; + + virtual int rnd_init() = 0; + virtual int rnd_next_block(parallel_reader_data_frame_t *data_frame) = 0; + virtual int rnd_end() = 0; + + virtual int read_range_init(uint keynr, key_range *min_key, key_range *max_key) = 0; + virtual int read_range_next_block(parallel_reader_data_frame_t *data_frame) = 0; + virtual int read_range_end() = 0; + virtual int condition_pushdown(Item *cond, Item *left) = 0; + + virtual int index_init(int keyno, bool asc) = 0; + virtual int index_next_block(parallel_reader_data_frame_t *data_frame) = 0; + virtual int index_end() = 0; +}; +#endif + static const dd::String_type index_file_name_val_key("index_file_name"); static const uint ROW_ID_LENGTH = sizeof(uint64_t); @@ -447,24 +516,43 @@ public: uint max_supported_key_part_length( HA_CREATE_INFO *create_info) const override; - /** - @brief Called in test_quick_select to determine if indexes should be used. - we assume that the data pages is equal to the disk scans times. - @return How many seeks it will take to read through the whole table. + /** @brief + Called in test_quick_select to determine if indexes should be used. */ - double scan_time() override; + virtual double scan_time() override { + DBUG_TRACE; + return (ulonglong)(stats.records + stats.deleted) / 100 + 2; + } - /** - @brief This method will never be called if you do not implement indexes. - @return estimated cost of 'index only' scan + /** @brief + This method will never be called if you do not implement indexes. */ - virtual double index_only_read_time(uint keynr, double records) override; + virtual double read_time( + uint index, /*!< in: key number */ + uint ranges, /*!< in: how many ranges */ + ha_rows rows) /*!< in: estimated number of rows in the ranges */ override { + DBUG_TRACE; - /** - @brief This method will never be called if you do not implement indexes. - @return estimated time measured in disk seeks - */ - double read_time(uint index, uint ranges, ha_rows rows) override; + if (index != table->s->primary_key) { + /* Not clustered */ + return (handler::read_time(index, ranges, rows)); + } + + if (rows <= 2) { + return ((double)rows); + } + + /* Assume that the read time is proportional to the scan time for all + rows + at most one seek per range. */ + + double time_for_scan = scan_time(); + + if (stats.records < rows) { + return (time_for_scan); + } + + return (ranges + (double)rows / (double)stats.records * time_for_scan); + } bool inplace_alter_table( TABLE *altered_table MY_ATTRIBUTE((unused)), @@ -491,6 +579,8 @@ public: int index_end() override; + int cmp_ref(const uchar *ref1, const uchar *ref2) const override; + int index_read(uchar *buf, const uchar *key, uint key_len, ha_rkey_function find_flag) override; int index_read_last(uchar *buf, const uchar *key_ptr, uint key_len) override; @@ -596,6 +686,19 @@ public: */ int rnd_pos(uchar *buf, uchar *pos) override; ///< required +#if FEATURE_FOR_EVERSQL + // for the integration with the new framework for parallel query from EverSQL side + ParallelReaderHandler* create_parallel_reader_handler(Parallel_reader_handler_config_t *prh_config) override; + void close_parallel_reader_handler(ParallelReaderHandler* prh) override; +#else + // for build with MySQL + ParallelReaderHandler* create_parallel_reader_handler(Parallel_reader_handler_config_t *prh_config); + void close_parallel_reader_handler(ParallelReaderHandler* prh); +#endif + + int split_rnd_scan(uint32_t part_id, uint32_t subpart_id, ctc_index_paral_range_t* paral_range, + int expected_parallel_degree, uint64_t *query_scn, uint64_t *ssn); + int prefetch_and_fill_record_buffer(uchar *buf, ctc_prefetch_fn); void fill_record_to_rec_buffer(); void reset_rec_buf(bool is_prefetch = false); @@ -855,6 +958,10 @@ public: virtual int get_cbo_stats_4share(); + bool m_ror_intersect = false; + + void set_ror_intersect(); + /** Pointer to Cond pushdown */ ctc_conds *m_cond = nullptr; Item *m_pushed_conds = nullptr; @@ -1000,8 +1107,6 @@ bool is_starting(); bool ctc_is_temporary(const dd::Table *table_def); int32_t ctc_get_cluster_role(); -void ctc_set_mysql_read_only(); -void ctc_reset_mysql_read_only(); int alloc_str_mysql_mem(ctc_cbo_stats_t *cbo_stats, uint32_t part_num, TABLE *table); void free_columns_cbo_stats(ctc_cbo_stats_column_t *ctc_cbo_stats_columns, bool *is_str_first_addr, TABLE *table); diff --git a/storage/ctc/ha_ctc_ddl.h b/storage/ctc/ha_ctc_ddl.h index 1522bf9..8d6bc1a 100644 --- a/storage/ctc/ha_ctc_ddl.h +++ b/storage/ctc/ha_ctc_ddl.h @@ -54,6 +54,8 @@ just having n_fields, n_uniq and the lengths of the columns. */ #define CTC_DDL_PROTOBUF_MSG_STACK_SIZE (4 * 1024) // < 4kb用栈内存,大于4kb用堆内存 #define CTC_DDL_PROTOBUF_MSG_SIZE (1024 * 1024 * 10) // 10M +#define CTC_MAX_SET_VAR_NUM 8 + typedef enum { CTC_CREATE_IF_NOT_EXISTS = 0x00000001, CTC_CREATE_OR_REPLACE = 0x00000002, @@ -173,7 +175,7 @@ static map mysql_collate_num_to_ctc_type = { typedef struct { char base_name[SMALL_RECORD_SIZE]; char var_name[SMALL_RECORD_SIZE]; - char var_value[CTC_MAX_VAR_VALUE_LEN]; + char var_value[MAX_DDL_SQL_LEN]; uint32_t options; bool var_is_int; } set_var_info; diff --git a/storage/ctc/ha_ctc_pq.cc b/storage/ctc/ha_ctc_pq.cc new file mode 100644 index 0000000..1a67a72 --- /dev/null +++ b/storage/ctc/ha_ctc_pq.cc @@ -0,0 +1,515 @@ +/* + Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "ha_ctc_pq.h" +#include "srv_mq_msg.h" +#include "decimal_convert.h" // CT_ERROR +#include "my_alloc.h" +#include "sql/mysqld_thd_manager.h" +#include "datatype_cnvrtr.h" +#include "ctc_error.h" +#include "sql/table.h" +#include "mysql/plugin.h" +#include "ctc_log.h" +#include "ha_ctcpart.h" +#include "ha_ctc.h" + +constexpr uint64 INVALID_VALUE64 = 0xFFFFFFFFFFFFFFFFULL; +static std::mutex parallel_reader_thread_mutex; +static int parallel_reader_thread_running = 0; +constexpr int MAX_PARALLEL_READ_THREADS = 256; +int CtcParallelReaderHandler::open_table(ctc_handler_t *new_tch) +{ + // assuming all table sent to this PRHandler as non-temp, non-system table, + // so a simple split over normalized_path would suffice. + // following logic is a shameless copy from ha_ctc::open with following difference: + // a. no longer use information from thd or sess_ctx + // b. don't write back updated tch to sess_ctx + char db_name[SMALL_RECORD_SIZE] = {0}; + char table_name[SMALL_RECORD_SIZE] = {0}; + bool is_tmp_table = false; + ctc_split_normalized_name(m_table->s->normalized_path.str, db_name, + SMALL_RECORD_SIZE, table_name, SMALL_RECORD_SIZE, &is_tmp_table); + ctc_copy_name(table_name, m_table->s->table_name.str, SMALL_RECORD_SIZE); + + ct_errno_t ret = (ct_errno_t) ctc_open_table(new_tch, table_name, db_name); + return ret; +} + +ctc_handler_t CtcParallelReaderHandler::construct_new_tch(ctc_handler_t origin_tch) +{ + return { + .inst_id = origin_tch.inst_id, + // fetch a thd_id from Global_THD_manager, shall be return in deinitialize + .thd_id = Global_THD_manager::get_instance()->get_new_thread_id(), + // part_no, differs according to splitted task + .part_id = INVALID_PART_ID, + // subpart_no, same as above + .subpart_id = INVALID_PART_ID, + .query_id = origin_tch.query_id, + // sess_addr, will be allocated through + // ctc_open_table() -> ctc_get_or_new_session() + .sess_addr = INVALID_VALUE64, + // ctx_addr, will be allocated through + // ctc_open_table() -> init_ctc_ctx_and_open_dc() + .ctx_addr = INVALID_VALUE64, + // cursor_addr, a INVALID_VALUE64 for uninitialized session + .cursor_addr = INVALID_VALUE64, + // pre_sess_addr, always zero as we don't care about + // recover from other session etc thing + .pre_sess_addr = 0, + // cursor_ref, the cursor count, zero for uninitialized session + .cursor_ref = 0, + // bind_core, would be assigned by cantian side + .bind_core = 0, + .sql_command = origin_tch.sql_command, + .sql_stat_start = origin_tch.sql_stat_start, + .change_data_capture = origin_tch.change_data_capture, + // cursor_valid set to false + .cursor_valid = false, + // is_broadcast kept false as only non-temp, non system query will be here. + .is_broadcast = false, + // should always be false since no sys table request + // shall be route to CtcParallelReaderHandler. + .read_only_in_ct = origin_tch.read_only_in_ct, + .msg_buf = nullptr + }; +} + +int CtcParallelReaderHandler::save_task(ctc_index_paral_range_t *result_paral_range, + uint32_t part_id, uint32_t subpart_id, uint64_t query_scn, uint64_t ssn) +{ + lock_guard lock(m_work_mutex); + for (uint32_t i = 0; i < result_paral_range->workers; i++) { + auto node = (LIST *) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(LIST), MYF(MY_WME | MY_ZEROFILL)); + auto data = (ctcpart_scan_range_t *) my_malloc(PSI_NOT_INSTRUMENTED, + sizeof(ctcpart_scan_range_t), MYF(MY_WME)); + if (node == nullptr || data == nullptr) { + my_free(node); + my_free(data); + return CT_ERROR; + } + memcpy(&data->range, result_paral_range->range[i], sizeof(ctc_scan_range_t)); + data->part = { + .part_id = part_id, + .subpart_id = subpart_id, + }; + data->query_scn = query_scn; + data->ssn = ssn; + node->data = data; + m_paral_range = list_add(m_paral_range, node); + }; + return CT_SUCCESS; +}; + +ctcpart_scan_range_t* CtcParallelReaderHandler::fetch_range() +{ + lock_guard lock(m_work_mutex); + if (m_paral_range == nullptr) { + return nullptr; + } + ctcpart_scan_range_t *scan_range = static_cast(m_paral_range->data); + LIST *old_node = m_paral_range; + m_paral_range = list_delete(m_paral_range, m_paral_range); + my_free(old_node); + return scan_range; +}; + +// If we don't have enough thread count left, it's EXPECTED to exit early. +void CtcParallelReaderHandler::acquire_parallel_thread_count_from_global( + int expected_dop, int dop_thd_var, int global_dop_var) +{ + m_worker_count = 0; + int worker_count_to_acquire = 0; + + if (expected_dop != 0) { + // future-proof to potential EverSQL side change. + worker_count_to_acquire = expected_dop > MAX_PARALLEL_READ_THREADS ? MAX_PARALLEL_READ_THREADS: expected_dop; + } else { + // according to current status of EverSQL side's code + // expected_dop will always be zero and it's left to us to decide dop, + // thus a ctc_parallel_read_threads thd variable is introduced + worker_count_to_acquire = dop_thd_var; + } + + if (worker_count_to_acquire > global_dop_var) { + // fool-proof to potential bad user provided sysvar + worker_count_to_acquire = global_dop_var; + } + + std::unique_lock parallel_reader_thread_mutex_lock(parallel_reader_thread_mutex); + if (worker_count_to_acquire + parallel_reader_thread_running > global_dop_var) { + return ; + } + + parallel_reader_thread_running += worker_count_to_acquire; + m_worker_count = worker_count_to_acquire; + return ; +} + +void CtcParallelReaderHandler::release_parallel_thread_count_back_to_global() +{ + std::lock_guard parallel_reader_thread_mutex_lock(parallel_reader_thread_mutex); + parallel_reader_thread_running -= m_worker_count; +} + +// CtcParallelReaderHandler is pretty much useless without an initialize call, DO remember to call this +int CtcParallelReaderHandler::initialize(TABLE *table, int expected_dop, + ctc_handler_t origin_tch, int dop_thd_var, int global_dop_var) +{ + m_table = table; + + acquire_parallel_thread_count_from_global(expected_dop, dop_thd_var, global_dop_var); + if (m_worker_count == 0) { + return CT_ERROR; + } + + m_work_tuples = (pq_work_tuple *) my_malloc(PSI_NOT_INSTRUMENTED, + sizeof(pq_work_tuple) * m_worker_count, MYF(MY_WME | MY_ZEROFILL)); + + m_my_buf_for_read = (char **) my_malloc(PSI_NOT_INSTRUMENTED, + sizeof(char *) * m_worker_count, MYF(MY_WME | MY_ZEROFILL)); + m_buf_for_read_count = m_worker_count - 1; + + if (m_work_tuples == nullptr || m_my_buf_for_read == nullptr) { + // free up here to make sure we don't mixed up mem alloc + // failure with other fail path + my_free(m_work_tuples); + my_free(m_my_buf_for_read); + m_buf_for_read_count = 0; + return CT_ERROR; + } + + // in the initialize call, we shall still be in the mysql context, + // the following steps CtcParallelReaderHandler shall be done before any rnd_next_block call: + // 0. initialize all field of CtcParallelReaderHandler + m_paral_range = nullptr; + + // 1. create workers (mimicked through different tch & multiple thread + // from a thread pool within duckdb context) + // 2. make ctc_open_table call for each tch so it have a + // valid (sess_addr, ctx_addr) tuple for use + for (int i = 0; i < m_worker_count; i++) { + ctc_handler_t new_worker_tch = construct_new_tch(origin_tch); + open_table(&new_worker_tch); + + m_work_tuples[i] = { + .tch = new_worker_tch, + .prefetch_buf = nullptr, + .current_offset = 0, + .current_entry_index = 0, + .record_lens = {0}, + .fetched_num = 0, + .in_use = false, + }; + } + + // 3. prepare the mysql column format + m_col_offsets = (ulong *) my_malloc(PSI_NOT_INSTRUMENTED, + sizeof(ulong) * CTC_MAX_COLUMNS, MYF(MY_WME | MY_ZEROFILL)); + m_null_byte_offsets = (ulong *) my_malloc(PSI_NOT_INSTRUMENTED, + sizeof(ulong) * CTC_MAX_COLUMNS, MYF(MY_WME | MY_ZEROFILL)); + m_null_bitmasks = (ulong *) my_malloc(PSI_NOT_INSTRUMENTED, + sizeof(ulong) * CTC_MAX_COLUMNS, MYF(MY_WME | MY_ZEROFILL)); + if (m_col_offsets == nullptr || m_null_byte_offsets == nullptr || m_null_bitmasks == nullptr) { + return CT_ERROR; + } + m_ncols = 0; + m_row_len = 0; + generate_mysql_record_row_desc(*m_table, &m_ncols, &m_row_len, m_col_offsets, + m_null_bitmasks, m_null_byte_offsets, m_table->read_set); + m_cantian_rec_len = get_cantian_record_length(m_table); + + // 1. prepare a char* for parallel_reader_data_frame_t->m_buf so we can avoid + // repetitive malloc-and-free, this shall only store record converted to + // msyql representation, aligned with mysql_row_desc_t.m_row_len + CTC_RETURN_IF_NOT_ZERO(my_alloc_data_frame_buf()); + // 2. allocate m_prefetch_buf for rnd_next_block use, directly from cantian + // side with cantian representation, similar to + // prefetch_and_fill_record_buffer(buf, ctc_rnd_prefetch), length may be varied + CTC_RETURN_IF_NOT_ZERO(ctc_alloc_ctc_prefetch_buf()); + return CT_SUCCESS; +} + +void CtcParallelReaderHandler::deinitialize() +{ + release_parallel_thread_count_back_to_global(); + // free all mysql desc etc + if (m_col_offsets != nullptr) { + my_free(m_col_offsets); + m_col_offsets = nullptr; + } + if (m_null_byte_offsets != nullptr) { + my_free(m_null_byte_offsets); + m_null_byte_offsets = nullptr; + } + if (m_null_bitmasks != nullptr) { + my_free(m_null_bitmasks); + m_null_bitmasks = nullptr; + } + std::lock_guard worker_lock(m_worker_mutex); + for (long i = 0; i < m_worker_count; i++) { + my_free(m_my_buf_for_read[i]); + ctc_free_buf(&(m_work_tuples[i].tch), m_work_tuples[i].prefetch_buf); + + if (m_work_tuples[i].tch.cursor_valid) { + ctc_rnd_end(&(m_work_tuples[i].tch)); + } + ctc_close_table(&(m_work_tuples[i].tch)); + ctc_close_session(&(m_work_tuples[i].tch)); + // symmetrical to get_new_thread_id in construct_new_tch + Global_THD_manager::get_instance()->release_thread_id(m_work_tuples[i].tch.thd_id); + } + my_free(m_work_tuples); + my_free(m_my_buf_for_read); + + std::lock_guard work_lock(m_work_mutex); + // ideally we should have exhausted all work entry in m_paral_range for a + // full table by-page scan, but LIMIT or similar sub-clause may cause + // leftovers in m_paral_range + list_free(m_paral_range, true); + m_paral_range = nullptr; + return ; +} + +int CtcParallelReaderHandler::rnd_init() +{ + return CT_SUCCESS; +} + +void CtcParallelReaderHandler::get_work_tuple(int *work_tuple_index) +{ + for (int i = 0; i < m_worker_count; i++) { + if (m_work_tuples[i].tch.cursor_valid && m_work_tuples[i].fetched_num != 0 && m_work_tuples[i].in_use == false) { + // found a fetched range setup in this work tuple, leftover record still + // in buffer and didn't have an EOF signal for this range yet. + // continue reading from this work tuple + *work_tuple_index = i; + return ; + } + } + + // didn't find any work tuple with fetched range, just find any one not in use + for (int i = 0; i < m_worker_count; i++) { + if (m_work_tuples[i].in_use == false) { + *work_tuple_index = i; + return ; + } + } +} + +int CtcParallelReaderHandler::prepare_work_tuple(pq_work_tuple *work_tuple, bool need_new_range) +{ + int ret = CT_SUCCESS; + if (work_tuple->tch.cursor_valid && (!need_new_range)) { + // valid cursor and we don't explicitly request a new range + return CT_SUCCESS; + } + + ctcpart_scan_range_t *scan_range = fetch_range(); + if (scan_range == nullptr) { + // exhausted all potential scan range + return CT_ERROR; + } + + // close existing one we have on work_tuple.tch and open a new one + ret = ctc_rnd_end(&work_tuple->tch); + if (ret != CT_SUCCESS) { + my_free(scan_range); + return ret; + } + + work_tuple->tch.part_id = scan_range->part.part_id; + work_tuple->tch.subpart_id = scan_range->part.subpart_id; + // the last parameter nullptr is left for condition pushdown + ret = ctc_rnd_init(&work_tuple->tch, EXP_CURSOR_ACTION_SELECT, SELECT_ORDINARY, nullptr); + if (ret != CT_SUCCESS) { + my_free(scan_range); + return ret; + } + + ret = ctc_pq_set_cursor_range(&work_tuple->tch, scan_range->range.l_page, scan_range->range.r_page, + scan_range->query_scn, scan_range->ssn); + my_free(scan_range); + return ret; +} + +void CtcParallelReaderHandler::convert_prefetch_buffer_to_mysql(parallel_reader_data_frame_t *df, + pq_work_tuple *work_tuple) +{ + df->m_actual_data_size = 0; + df->m_buf_size = 0; + // convert leftovers or freshly fetched entry to mysql side representation + for (;work_tuple->current_entry_index < work_tuple->fetched_num;) { + index_info_t index = { + .active_index = MAX_INDEXES, + .max_col_idx = (uint) m_ncols, + }; + int cantian_record_buf_size = work_tuple->record_lens[work_tuple->current_entry_index]; + record_buf_info_t record_buf = { + .cantian_record_buf = work_tuple->prefetch_buf + work_tuple->current_offset, + .mysql_record_buf = (uchar *) df->m_buf + df->m_actual_data_size, + .cantian_record_buf_size = &cantian_record_buf_size, + }; + cantian_record_to_mysql_record(*m_table, &index, &record_buf, work_tuple->tch, nullptr); + + df->m_actual_data_size += m_row_len; + work_tuple->current_offset += work_tuple->record_lens[work_tuple->current_entry_index]; + work_tuple->current_entry_index ++; + + if (df->m_actual_data_size + m_row_len >= BIG_RECORD_SIZE) { + // destination buffer can't handle more record + break; + } + } +} + +// EverSQL side always segfault for non CT_SUCCESS ret value for rnd_next_block, always return CT_SUCCESS +// To indicate a failed fetch or an EOF, use m_actual_data_size = 0 as a signal. +// df->m_buf_size and df->m_buf_id serves no use for this scenario. +int CtcParallelReaderHandler::rnd_next_block(parallel_reader_data_frame_t *df) +{ + m_worker_mutex.lock(); + if (m_buf_for_read_count < 0) { + // exhausted all m_my_buf_for_read, scenario would be like below: + // 1. reset_data_frame hasn't been called yet + // 2. EverSQL has bigger parallel degree than we have. + // either way, we need to return an EOF to calm them down. + df->m_actual_data_size = 0; + df->m_buf = nullptr; + m_worker_mutex.unlock(); + return CT_SUCCESS; + } + + int work_tuple_index = -1; + get_work_tuple(&work_tuple_index); + if (work_tuple_index == -1) { + // eversql side use more dop than guidance scenario + df->m_actual_data_size = 0; + df->m_buf = nullptr; + m_worker_mutex.unlock(); + return CT_SUCCESS; + } + + m_work_tuples[work_tuple_index].in_use = true; + pq_work_tuple work_tuple = m_work_tuples[work_tuple_index]; + + // df->m_buf will be returned to CtcParallelReaderHandler by reset_data_frame + df->m_buf = m_my_buf_for_read[m_buf_for_read_count]; + m_buf_for_read_count--; + + m_worker_mutex.unlock(); + + bool fetched = false; + bool need_new_range = false; + if (work_tuple.fetched_num <= work_tuple.current_entry_index || work_tuple.fetched_num == 0) { + // the prefetch_buf in work_tuple exhausted and should be fetching new now + while (!fetched) { + int ret = prepare_work_tuple(&work_tuple, need_new_range); + if (ret != CT_SUCCESS) { + // preparation step for ctc_rnd_prefetch failed, this mostly + // indicate an OOM scenario or corrupted tch, return an + // EOF to clean up this worker thread + break; + } + + // attempt to do a ctc_rnd_prefetch to do bulk read here; + // rowid array placeholders which would be disposed immediately + // as won't have position() call during parallel query. + uint64_t rowid_placeholder[MAX_BATCH_FETCH_NUM]; + ret = ctc_rnd_prefetch(&work_tuple.tch, work_tuple.prefetch_buf, &work_tuple.record_lens[0], + &work_tuple.fetched_num, rowid_placeholder, m_cantian_rec_len); + if (work_tuple.fetched_num == 0 && (ret == CT_SUCCESS)) { + need_new_range = true; + } else { + fetched = true; + work_tuple.current_entry_index = 0; + work_tuple.current_offset = 0; + } + } + } + + convert_prefetch_buffer_to_mysql(df, &work_tuple); + + m_worker_mutex.lock(); + work_tuple.in_use = false; + m_work_tuples[work_tuple_index] = work_tuple; + m_worker_mutex.unlock(); + + // EverSQL side WON'T call reset_data_frame when df->m_actual_data_size == 0, return df->m_buf back here + // otherwise, the buffer shall be add back in reset_data_frame + if (df->m_actual_data_size == 0) { + reset_data_frame(df); + } + return CT_SUCCESS; +} + +int CtcParallelReaderHandler::my_alloc_data_frame_buf() +{ + // unavoidable to do malloc here as the converted result always need a place + // to store in, no matter it's in single run mode or not + std::lock_guard lock(m_worker_mutex); + for (int i = 0; i < m_worker_count; i++) { + m_my_buf_for_read[i] = (char *) my_malloc(PSI_NOT_INSTRUMENTED, + sizeof(char) * BIG_RECORD_SIZE, MYF(MY_WME | MY_ZEROFILL)); + if (m_my_buf_for_read[i] == nullptr) { + return convert_ctc_error_code_to_mysql(ERR_ALLOC_MEMORY); + } + } + return CT_SUCCESS; +} + +// ctc_alloc_buf prefetch_buf for temporary space between ctc and kernel +int CtcParallelReaderHandler::ctc_alloc_ctc_prefetch_buf() +{ + std::lock_guard lock(m_worker_mutex); + for (int i = 0; i < m_worker_count; i++) { + m_work_tuples[i].prefetch_buf = (uchar *)ctc_alloc_buf(&(m_work_tuples[i].tch), BIG_RECORD_SIZE); + if (m_work_tuples[i].prefetch_buf == nullptr) { + return convert_ctc_error_code_to_mysql(ERR_ALLOC_MEMORY); + } + } + return CT_SUCCESS; +} + +int CtcParallelReaderHandler::rnd_end() +{ + return CT_SUCCESS; +} + +ParallelReaderHandler::mysql_row_desc_t CtcParallelReaderHandler::get_row_info_for_parse() +{ + return ParallelReaderHandler::mysql_row_desc_t { + .m_ncols = m_ncols, + .m_row_len = m_row_len, + .m_col_offsets = m_col_offsets, + .m_null_byte_offsets = m_null_byte_offsets, + .m_null_bitmasks = m_null_bitmasks, + }; +} + +void CtcParallelReaderHandler::reset_data_frame(parallel_reader_data_frame_t *df) +{ + std::lock_guard lock(m_worker_mutex); + if (df->m_buf != nullptr) { + m_buf_for_read_count ++; + m_my_buf_for_read[m_buf_for_read_count] = df->m_buf; + df->m_buf = nullptr; + } + return; +}; diff --git a/storage/ctc/ha_ctc_pq.h b/storage/ctc/ha_ctc_pq.h new file mode 100644 index 0000000..517d617 --- /dev/null +++ b/storage/ctc/ha_ctc_pq.h @@ -0,0 +1,168 @@ +/* + Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2.0, + as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License, version 2.0, for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __HA_CTC_PQ_H__ +#define __HA_CTC_PQ_H__ + +#include +#include +#include +#include "my_inttypes.h" +#include "my_list.h" +#include "my_base.h" +#include "ha_ctc.h" +#include "ctc_log.h" + +// The following exception is for one-shot use inside ha_ctc_pq.{h/cpp} +// and shall NOT be used anywhere else. +// This method shall be eliminated post stable-integration with index scan and +// range index scan. +class CtcPQNotImplemented : public std::logic_error { +public: + CtcPQNotImplemented() : std::logic_error("Function not yet implemented") + { + } +}; + +struct pq_work_tuple { + ctc_handler_t tch; + uchar *prefetch_buf; + uint64_t current_offset; + uint32_t current_entry_index; + uint16_t record_lens[MAX_BATCH_FETCH_NUM]; + uint32_t fetched_num; + bool in_use; +}; + +class CtcParallelReaderHandler : public ParallelReaderHandler { +public: + // acquired worker count + int m_worker_count; + int m_cantian_rec_len; + CtcParallelReaderHandler() = default; + ~CtcParallelReaderHandler() = default; + int initialize(TABLE *table, int expected_dop, ctc_handler_t origin_tch, + int dop_thd_var, int global_dop_var); + void deinitialize(); + + // fetch row info, this shall be called only once in mysql context + ParallelReaderHandler::mysql_row_desc_t get_row_info_for_parse() override; + + // free up parallel_reader_data_frame_t allocated in + // {index/rnd/read_range}_next_block, shall be called once every time + void reset_data_frame(parallel_reader_data_frame_t *df) override; + + // by-page scan related method + // start of a by-page scan, only get called in an mysql context for once + int rnd_init() override; + + // this shall be called by executor thread in parallel, return through a + // locally allocated parallel_reader_data_frame_t + int rnd_next_block(parallel_reader_data_frame_t *df) override; + + // end of a by-page scan + int rnd_end() override; + + int save_task(ctc_index_paral_range_t *result_paral_range, uint32_t part_id, + uint32_t subpart_id, uint64_t query_scn, uint64_t ssn); + + ctc_handler_t construct_new_tch(ctc_handler_t origin_tch); + int open_table(ctc_handler_t *new_tch); + + // the following are just api placeholder for future use + + // ranged scan + int read_range_init(uint keynr, key_range *min_key, key_range *max_key) override + { + UNUSED_PARAM(keynr); + UNUSED_PARAM(min_key); + UNUSED_PARAM(max_key); + throw CtcPQNotImplemented(); + } + + int read_range_next_block(parallel_reader_data_frame_t *df) override + { + UNUSED_PARAM(df); + throw CtcPQNotImplemented(); + } + + int read_range_end() override + { + throw CtcPQNotImplemented(); + } + + int condition_pushdown(Item *cond, Item *left) override + { + UNUSED_PARAM(cond); + UNUSED_PARAM(left); + throw CtcPQNotImplemented(); + } + + // index based full table scan + int index_init(int keyno, bool asc) override + { + UNUSED_PARAM(keyno); + UNUSED_PARAM(asc); + throw CtcPQNotImplemented(); + } + + int index_next_block(parallel_reader_data_frame_t *df) override + { + UNUSED_PARAM(df); + throw CtcPQNotImplemented(); + } + + int index_end() override + { + throw CtcPQNotImplemented(); + } + +private: + // fields saved for mysql_row_desc_t + ulong m_ncols; + ulong m_row_len; + ulong *m_col_offsets; + ulong *m_null_byte_offsets; + ulong *m_null_bitmasks; + + // the array to all ctc_handler_t that we are calling cantian side on behalf of + // to get a valid worker every {}_next_block call, mutex_guard + // worker_mutex and pop one from ctc_handler_t + std::mutex m_worker_mutex; + pq_work_tuple *m_work_tuples; + + // m_buf_for_read_count always point to next available m_my_buf_for_read + int m_buf_for_read_count; + char **m_my_buf_for_read; + + std::mutex m_work_mutex; + LIST *m_paral_range; + TABLE *m_table; // TABLE saved for ease of converting record + + ctcpart_scan_range_t *fetch_range(); + void free_list(); + + int my_alloc_data_frame_buf(); + int ctc_alloc_ctc_prefetch_buf(); + void acquire_parallel_thread_count_from_global(int expected_dop, int dop_thd_var, int global_dop_var); + void release_parallel_thread_count_back_to_global(); + void get_work_tuple(int *work_tuple_index); + int prepare_work_tuple (pq_work_tuple *work_tuple, bool need_new_range); + void convert_prefetch_buffer_to_mysql(parallel_reader_data_frame_t *df, pq_work_tuple *work_tuple); +}; + +#endif \ No newline at end of file diff --git a/storage/ctc/ha_ctcpart.cc b/storage/ctc/ha_ctcpart.cc index 7ed0db6..e05ff7b 100644 --- a/storage/ctc/ha_ctcpart.cc +++ b/storage/ctc/ha_ctcpart.cc @@ -57,8 +57,6 @@ #include "sql/dd/types/partition.h" #include "sql/dd/string_type.h" -#define INVALID_PART_ID (uint32)0xFFFFFFFF; - extern handlerton *get_ctc_hton(); extern uint32_t ctc_update_analyze_time; @@ -75,8 +73,9 @@ static uint32_t get_ct_part_no(uint num_subparts, uint part_id) { return (uint32_t)part_no; } -static bool get_used_partitions(partition_info *part_info, - uint32_t **part_ids,uint32_t **subpart_ids, uint32_t *used_parts) { +bool get_used_partitions(partition_info *part_info, + uint32_t **part_ids, uint32_t **subpart_ids, uint32_t *used_parts) +{ *used_parts = part_info->num_partitions_used(); if (*used_parts > 0) { *part_ids = (uint32_t *)my_malloc(PSI_NOT_INSTRUMENTED, (*used_parts) * sizeof(uint32_t), MYF(MY_WME)); @@ -405,6 +404,32 @@ void ha_ctcpart::position_in_last_part(uchar *ref_arg, const uchar *record) { reset_partition(part_id); } +int ha_ctcpart::key_and_rowid_cmp(KEY **key_info, uchar *a, uchar *b) { + int cmp = key_rec_cmp(key_info, a, b); + if (cmp != 0) { + return (cmp); + } + + /* We must compare by rowid, which is added before the record, in the priority queue. */ + return (ctc_cmp_cantian_rowid((rowid_t *)(a - ROW_ID_LENGTH), (rowid_t *)(b - ROW_ID_LENGTH))); +} + +int ha_ctcpart::extra(enum ha_extra_function operation) { + if (operation == HA_EXTRA_SECONDARY_SORT_ROWID) { + m_ref_usage = Partition_helper::REF_USED_FOR_SORT; + m_queue->m_fun = key_and_rowid_cmp; + return (0); + } + return (ha_ctc::extra(operation)); +} + +int ha_ctcpart::cmp_ref(const uchar *ref1, const uchar *ref2) const { + DBUG_TRACE; + int cmp = ha_ctc::cmp_ref(ref1 + PARTITION_BYTES_IN_POS, ref2 + PARTITION_BYTES_IN_POS); + + return (cmp); +} + /** Get a row from a position. Fetches a row from the table based on a row reference. @@ -818,41 +843,14 @@ enum row_type ha_ctcpart::get_partition_row_type(const dd::Table *partition_tabl return ROW_TYPE_NOT_USED; } -double ha_ctcpart::scan_time() { - DBUG_TRACE; - double sum_data_page = 0.0; - - if (m_part_share != nullptr && m_part_share->cbo_stats != nullptr) { - uint part_num = m_is_sub_partitioned ? table->part_info->num_parts * table->part_info->num_subparts : - table->part_info->num_parts; - for (uint i = m_part_info->get_first_used_partition(); i < part_num; - i = m_part_info->get_next_used_partition(i)) { - sum_data_page += m_part_share->cbo_stats->ctc_cbo_stats_table[i].blocks; - } - } - return sum_data_page; -} - void ha_ctcpart::info_low() { stats.records = 0; - uint total_row_len = 0; if (m_part_share->cbo_stats != nullptr) { - uint total_part_num = m_is_sub_partitioned ? table->part_info->num_parts * table->part_info->num_subparts : + uint part_num = m_is_sub_partitioned ? table->part_info->num_parts * table->part_info->num_subparts : table->part_info->num_parts; - uint curr_part_num = 0; - stats.block_size = m_part_share->cbo_stats->page_size; - - for (uint part_id = m_part_info->get_first_used_partition(); part_id < total_part_num; + for (uint part_id = m_part_info->get_first_used_partition(); part_id < part_num; part_id = m_part_info->get_next_used_partition(part_id)) { stats.records += m_part_share->cbo_stats->ctc_cbo_stats_table[part_id].estimate_rows; - if (m_part_share->cbo_stats->ctc_cbo_stats_table[part_id].avg_row_len != 0) { - total_row_len += m_part_share->cbo_stats->ctc_cbo_stats_table[part_id].avg_row_len; - curr_part_num++; - } - } - - if (curr_part_num > 0) { - stats.mean_rec_length = total_row_len / curr_part_num; } } } @@ -1039,7 +1037,7 @@ int ha_ctcpart::initialize_cbo_stats() { ctc_log_error("alloc mem failed, m_part_share->cbo_stats size(%lu)", sizeof(ctc_cbo_stats_t)); return ERR_ALLOC_MEMORY; } - *m_part_share->cbo_stats = {0, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr, 0}; + *m_part_share->cbo_stats = {0, 0, 0, 0, 0, nullptr, 0, nullptr, nullptr}; m_part_share->cbo_stats->part_cnt = part_num; @@ -1057,8 +1055,6 @@ int ha_ctcpart::initialize_cbo_stats() { } for (uint i = 0; i < part_num; i++) { m_part_share->cbo_stats->ctc_cbo_stats_table[i].estimate_rows = 0; - m_part_share->cbo_stats->ctc_cbo_stats_table[i].avg_row_len = 0; - m_part_share->cbo_stats->ctc_cbo_stats_table[i].blocks = 0; m_part_share->cbo_stats->ctc_cbo_stats_table[i].columns = (ctc_cbo_stats_column_t*)my_malloc(PSI_NOT_INSTRUMENTED, table->s->fields * sizeof(ctc_cbo_stats_column_t), MYF(MY_WME)); if (m_part_share->cbo_stats->ctc_cbo_stats_table[i].columns == nullptr) { diff --git a/storage/ctc/ha_ctcpart.h b/storage/ctc/ha_ctcpart.h index 863769f..ec4f903 100644 --- a/storage/ctc/ha_ctcpart.h +++ b/storage/ctc/ha_ctcpart.h @@ -213,6 +213,12 @@ class ha_ctcpart : public ha_ctc, const uchar *key, key_part_map keypart_map, enum ha_rkey_function find_flag) override; + static int key_and_rowid_cmp(KEY **key_info, uchar *a, uchar *b); + + int extra(enum ha_extra_function operation) override; + + int cmp_ref(const uchar *ref1, const uchar *ref2) const override; + /** Open an CTC table. @param[in] name table name @param[in] mode access mode @@ -392,8 +398,6 @@ class ha_ctcpart : public ha_ctc, bool equal_range_on_part_field(const key_range *start_key, const key_range *end_key); - double scan_time() override; - void info_low() override; int info(uint) override; @@ -444,4 +448,6 @@ static inline void cursor_clear_bit(int *cursor_set, uint bit) { (cursor_set)[bit / 8] &= ~(1 << (bit & 7)); } +bool get_used_partitions(partition_info *part_info, + uint32_t **part_ids, uint32_t **subpart_ids, uint32_t *used_parts); #endif /* ha_ctcpart_h */ \ No newline at end of file diff --git a/storage/ctc/srv_mq_msg.h b/storage/ctc/srv_mq_msg.h index 256f23b..d08876c 100644 --- a/storage/ctc/srv_mq_msg.h +++ b/storage/ctc/srv_mq_msg.h @@ -36,6 +36,29 @@ extern "C" { #define REG_MISMATCH_CTC_VERSION 501 #define REG_ALLOC_INST_ID_FAILED 502 +// duplicate req->worker_count and req->index_paral_range->workers, intent to do so to align with knl api. +struct get_index_paral_schedule_request { + ctc_handler_t tch; + int worker_count; // in and out param, expected DOP (degree of parallel), out as actually scheduled worker count. + char index_name[CTC_MAX_KEY_NAME_LENGTH + 1]; // in param, indicating the slot id used to fetch index param + ctc_scan_range_t *scan_range; // in param + ctc_index_paral_range_t *index_paral_range; // out param + uint64_t query_scn; // query_scn is of scn type, out param for first request, drop for the rest + bool reverse; + bool is_index_full; + int result; +}; + +// duplicate req->worker_count and req->paral_range->workers, intent to do so to align with knl api. +struct get_paral_schedule_request { + ctc_handler_t tch; + int worker_count; // in and out pararm + ctc_index_paral_range_t *paral_range; // out param, point to a range on shared memory allocated with ctc_malloc + uint64_t query_scn; // query_scn is of scn type, out param for first request, drop for the rest + uint64_t ssn; + int result; +}; + struct register_instance_request { uint32_t ctc_version; // ctc支持多版本的接口,格式为1.1.3=1001003,00作为点标记 int group_num; @@ -145,6 +168,8 @@ struct trx_begin_request { int result; ctc_trx_context_t trx_context; bool is_mysql_local; + struct timeval begin_time; + bool enable_stat; }; struct trx_commit_request { @@ -153,6 +178,7 @@ struct trx_commit_request { bool is_ddl_commit; int32_t csize; uint64_t *cursors; + char sql[MAX_DML_SQL_LEN]; }; struct trx_rollback_request { @@ -251,6 +277,34 @@ struct index_read_request { bool index_skip_scan; }; +struct pq_index_read_request { + bool sorted; + bool need_init; + uint8_t *record; + uint16_t record_len; + uint16_t find_flag; + char index_name[CTC_MAX_KEY_NAME_LENGTH + 1]; + uint16_t key_num; + int action; + int result; + ctc_handler_t tch; + ctc_select_mode_t mode; + ctc_conds *cond; + bool is_replace; + bool index_skip_scan; + ctc_scan_range_t scan_range; + uint64_t query_scn; +}; + +struct set_cursor_range_requst { + ctc_handler_t tch; + ctc_page_id_t l_page; + ctc_page_id_t r_page; + uint64_t query_scn; + uint64_t ssn; + int result; +}; + struct index_end_request { ctc_handler_t tch; int result; @@ -396,6 +450,11 @@ struct query_cluster_role_request { int result; }; +struct update_sample_size_request { + uint32_t sample_size; + bool need_persist; +}; + struct query_shm_file_num_request { uint32_t shm_file_num; bool cluster_ready; -- Gitee From 9aba903ad49ec1cefef14689702c1c9eea94e4e5 Mon Sep 17 00:00:00 2001 From: tolyrria <2292493757@qq.com> Date: Tue, 24 Dec 2024 15:50:24 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E5=90=88=E5=B9=B6=E5=86=B2=E7=AA=81?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- storage/ctc/ctc_srv_mq_stub.cc | 146 ---------------------------- storage/ctc/ha_ctc.cc | 172 --------------------------------- 2 files changed, 318 deletions(-) diff --git a/storage/ctc/ctc_srv_mq_stub.cc b/storage/ctc/ctc_srv_mq_stub.cc index d326dcb..7a90b42 100644 --- a/storage/ctc/ctc_srv_mq_stub.cc +++ b/storage/ctc/ctc_srv_mq_stub.cc @@ -1836,152 +1836,6 @@ int ctc_get_paral_schedule(ctc_handler_t *tch, uint64_t *query_scn, uint64_t *ss return result; } -// convert mysql side data to ctc message queue accepted request type and return; -int ctc_get_index_paral_schedule(ctc_handler_t *tch, uint64_t *query_scn, int *worker_count, - char* index_name, bool reverse, bool is_index_full, - ctc_scan_range_t *origin_scan_range, ctc_index_paral_range_t *index_paral_range) -{ - void *shm_inst = get_one_shm_inst(tch); - - get_index_paral_schedule_request *req = (get_index_paral_schedule_request*) - alloc_share_mem(shm_inst, sizeof(get_index_paral_schedule_request)); - if (req == NULL) { - ctc_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, - sizeof(get_index_paral_schedule_request)); - return ERR_ALLOC_MEMORY; - } - memset(req, 0, sizeof(get_index_paral_schedule_request)); - - req->tch = *tch; - req->worker_count = *worker_count; - memcpy(&req->index_name, index_name, sizeof(char) * (CTC_MAX_KEY_NAME_LENGTH + 1)); - req->scan_range = origin_scan_range; - req->query_scn = *query_scn; - req->reverse = reverse; - req->is_index_full = is_index_full; - // the index_paral_range is allocated outside this ctc_get_index_paral_schedule - // to avoid multiple redundent malloc-free pair in mrr scan. - req->index_paral_range = index_paral_range; - - int ret = ctc_mq_deal_func(shm_inst, CTC_FUNC_TYPE_GET_INDEX_PARAL_SCHEDULE, req, tch->msg_buf); - *tch = req->tch; - *query_scn = req->query_scn; - *worker_count = req->worker_count; - - free_share_mem(shm_inst, req); - if (ret == CT_SUCCESS) { - return req->result; - } - return ret; -} - -int ctc_pq_index_read(ctc_handler_t *tch, record_info_t *record_info, index_key_info_t *index_info, - ctc_scan_range_t scan_range, - ctc_select_mode_t mode, ctc_conds *cond, const bool is_replace, uint64_t query_scn) -{ - if (index_info == NULL) { - return ERR_GENERIC_INTERNAL_ERROR; - } - - void *shm_inst = get_one_shm_inst(tch); - pq_index_read_request *req = (pq_index_read_request*)alloc_share_mem(shm_inst, sizeof(pq_index_read_request)); - if (req == NULL) { - ctc_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(pq_index_read_request)); - return ERR_ALLOC_MEMORY; - } - memset(req, 0, sizeof(pq_index_read_request)); - - req->tch = *tch; - req->record = record_info->record; - req->record_len = 0; - req->mode = mode; - req->cond = cond; - req->is_replace = is_replace; - req->result = 0; - req->action = index_info->action; - req->need_init = index_info->need_init; - req->query_scn = query_scn; - - // the pointer in req->scan_range.{l/r}_key.buf will point to invalid address in cantian side. - memcpy(&req->scan_range, &scan_range, sizeof(ctc_scan_range_t)); - memcpy(&req->index_name, index_info->index_name, sizeof(char) * (CTC_MAX_KEY_NAME_LENGTH + 1)); - int result = ERR_CONNECTION_FAILED; - int ret = ctc_mq_deal_func(shm_inst, CTC_FUNC_TYPE_PQ_INDEX_READ, req, tch->msg_buf); - *tch = req->tch; - tch->sql_stat_start = req->tch.sql_stat_start; - if (ret == CT_SUCCESS) { - if (req->result == CT_SUCCESS) { - record_info->record_len = req->record_len; - assert(record_info->record_len < BIG_RECORD_SIZE); - } - result = req->result; - index_info->need_init = req->need_init; - } - - free_share_mem(shm_inst, req); - - return result; -} - -int ctc_pq_set_cursor_range(ctc_handler_t *tch, ctc_page_id_t l_page, ctc_page_id_t r_page, - uint64_t query_scn, uint64_t ssn) -{ - void *shm_inst = get_one_shm_inst(tch); - set_cursor_range_requst *req = (set_cursor_range_requst*)alloc_share_mem(shm_inst, sizeof(set_cursor_range_requst)); - if (req == NULL) { - ctc_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(set_cursor_range_requst)); - return ERR_ALLOC_MEMORY; - } - - req->tch = *tch; - req->l_page = l_page; - req->r_page = r_page; - req->query_scn = query_scn; - req->ssn = ssn; - int ret = ctc_mq_deal_func(shm_inst, CTC_FUNC_TYPE_PQ_SET_CURSOR_RANGE, req, tch->msg_buf); - *tch = req->tch; - free_share_mem(shm_inst, req); - if (ret == CT_SUCCESS) { - return req->result; - } - return ret; -} - -// this method call ct side for spliting a full table per-page scan to multi thread tasks -// the arg *paral_range should pointing at a mem range within shared memory. -int ctc_get_paral_schedule(ctc_handler_t *tch, uint64_t *query_scn, uint64_t *ssn, int *worker, - ctc_index_paral_range_t *paral_range) -{ - void *shm_inst = get_one_shm_inst(tch); - - get_paral_schedule_request *req = (get_paral_schedule_request*) - alloc_share_mem(shm_inst, sizeof(get_paral_schedule_request)); - if (req == NULL) { - ctc_log_error("alloc shm mem error, shm_inst(%p), size(%lu)", shm_inst, sizeof(get_paral_schedule_request)); - return ERR_ALLOC_MEMORY; - } - memset(req, 0, sizeof(get_paral_schedule_request)); - - req->tch = *tch; - req->query_scn = *query_scn; - req->paral_range = paral_range; - req->worker_count = *worker; - req->ssn = *ssn; - - int result = ERR_CONNECTION_FAILED; - int ret = ctc_mq_deal_func(shm_inst, CTC_FUNC_TYPE_GET_PARAL_SCHEDULE, req, tch->msg_buf); - - *tch = req->tch; - *worker = req->worker_count; - *query_scn = req->query_scn; - *ssn = req->ssn; - if (ret == CT_SUCCESS) { - result = req->result; - } - free_share_mem(shm_inst, req); - return result; -} - int ctc_query_cluster_role(bool *is_slave, bool *cantian_cluster_ready) { void *shm_inst = get_one_shm_inst(NULL); query_cluster_role_request *req = (query_cluster_role_request*) alloc_share_mem(shm_inst, sizeof(query_cluster_role_request)); diff --git a/storage/ctc/ha_ctc.cc b/storage/ctc/ha_ctc.cc index a32ac91..ab92ca6 100644 --- a/storage/ctc/ha_ctc.cc +++ b/storage/ctc/ha_ctc.cc @@ -295,61 +295,6 @@ static void update_sample_size(THD *thd, SYS_VAR *, void *, const void *save) } } -static MYSQL_SYSVAR_UINT(sample_size, ctc_sample_size, PLUGIN_VAR_RQCMDARG, - "The size of the statistical sample data, measured in megabytes (MB).", - check_sample_size, update_sample_size, - CTC_DEFAULT_SAMPLE_SIZE, CTC_MIN_SAMPLE_SIZE, CTC_MAX_SAMPLE_SIZE, 0); - -static mutex m_ctc_sample_size_mutex; -uint32_t ctc_sample_size; -static int check_sample_size(THD *, SYS_VAR *, void *save, struct st_mysql_value *value) -{ - longlong in_val; - value->val_int(value, &in_val); - - if (in_val < CTC_MIN_SAMPLE_SIZE || in_val >= CTC_MAX_SAMPLE_SIZE) { - std::stringstream error_str; - error_str << "The value " << in_val - << " is not within the range of accepted values for the option " - << "ctc_sample_size.The value must be between " - << CTC_MIN_SAMPLE_SIZE << " inclusive and " - << CTC_MAX_SAMPLE_SIZE << " exclusive."; - my_message(ER_WRONG_VALUE_FOR_VAR, error_str.str().c_str(), MYF(0)); - - return CT_ERROR; - } - - *(longlong *)save = in_val; - - return CT_SUCCESS; -} - -static void update_sample_size(THD *thd, SYS_VAR *, void *, const void *save) -{ - lock_guard lock(m_ctc_sample_size_mutex); - List_iterator_fast var_it(thd->lex->var_list); - var_it.rewind(); - set_var_base *var = nullptr; - string name_str; - while((var = var_it++)) { - if (typeid(*var) == typeid(set_var)) { - set_var *setvar = dynamic_cast(var); -#ifdef FEATURE_X_FOR_MYSQL_32 - name_str = setvar->m_var_tracker.get_var_name(); -#elif defined(FEATURE_X_FOR_MYSQL_26) - name_str = setvar->var->name.str; -#endif - if (name_str != "ctc_sample_size") { - continue; - } - bool need_persist = (setvar->type == OPT_PERSIST); - if (ctc_update_sample_size(*static_cast(save), need_persist) == CT_SUCCESS) { - ctc_sample_size = *static_cast(save); - } - } - } -} - static MYSQL_SYSVAR_UINT(sample_size, ctc_sample_size, PLUGIN_VAR_RQCMDARG, "The size of the statistical sample data, measured in megabytes (MB).", check_sample_size, update_sample_size, @@ -368,20 +313,10 @@ int32_t ctc_parallel_max_read_threads = 128; static MYSQL_SYSVAR_INT(parallel_max_read_threads, ctc_parallel_max_read_threads, PLUGIN_VAR_OPCMDARG, "Global Degree of Parallel for turbo plugin", nullptr, nullptr, 128, 1, CT_MAX_PARAL_QUERY, 0); -int32_t parallel_read_threads = 4; -static MYSQL_THDVAR_INT(parallel_read_threads, PLUGIN_VAR_OPCMDARG, - "Degree of Parallel for turbo plugin for a single table in single session", nullptr, nullptr, - 4, 1, CT_MAX_PARAL_QUERY, 0); - -int32_t ctc_parallel_max_read_threads = 128; -static MYSQL_SYSVAR_INT(parallel_max_read_threads, ctc_parallel_max_read_threads, PLUGIN_VAR_OPCMDARG, - "Global Degree of Parallel for turbo plugin", nullptr, nullptr, 128, 1, CT_MAX_PARAL_QUERY, 0); - // All global and session system variables must be published to mysqld before // use. This is done by constructing a NULL-terminated array of the variables // and linking to it in the plugin public interface. static SYS_VAR *ctc_system_variables[] = { - MYSQL_SYSVAR(sample_size), MYSQL_SYSVAR(sample_size), MYSQL_SYSVAR(lock_wait_timeout), MYSQL_SYSVAR(instance_id), @@ -663,7 +598,6 @@ void ha_ctc::prep_cond_push(const Item *cond) { Item *pushed_cond = nullptr; Item *remainder = nullptr; cond_push_term(item, pushed_cond, remainder, Item_func::COND_AND_FUNC); - cond_push_term(item, pushed_cond, remainder, Item_func::COND_AND_FUNC); m_pushed_conds = pushed_cond; m_remainder_conds = remainder; } @@ -1506,25 +1440,18 @@ static typename std::enable_if::type // no action here } -#ifdef METADATA_NORMALIZED -static void attachable_trx_update_pre_addr(THD *thd, ctc_handler_t *tch, bool set_to_pre_addr) { #ifdef METADATA_NORMALIZED static void attachable_trx_update_pre_addr(THD *thd, ctc_handler_t *tch, bool set_to_pre_addr) { if (thd->is_attachable_transaction_active() && (thd->tx_isolation == ISO_READ_UNCOMMITTED) && (thd->pre_sess_addr != 0) && thd->query_plan.get_command() == SQLCOM_RENAME_TABLE) { tch->pre_sess_addr = set_to_pre_addr ? thd->pre_sess_addr : 0; - && (thd->pre_sess_addr != 0) && thd->query_plan.get_command() == SQLCOM_RENAME_TABLE) { - tch->pre_sess_addr = set_to_pre_addr ? thd->pre_sess_addr : 0; } } #else -static void attachable_trx_update_pre_addr(THD *thd MY_ATTRIBUTE((unused)), -#else static void attachable_trx_update_pre_addr(THD *thd MY_ATTRIBUTE((unused)), ctc_handler_t *tch MY_ATTRIBUTE((unused)), bool set_to_pre_addr MY_ATTRIBUTE((unused))) { } #endif -#endif static void ctc_free_cursors_no_autocommit(THD *thd, ctc_handler_t *tch, thd_sess_ctx_s *sess_ctx) { if (!thd->in_multi_stmt_transaction_mode()) { @@ -2897,20 +2824,6 @@ void ha_ctc::set_ror_intersect() { #endif } -void ha_ctc::set_ror_intersect() { -#ifdef FEATURE_X_FOR_MYSQL_32 - if (table->reginfo.qep_tab && table->reginfo.qep_tab->access_path() && - table->reginfo.qep_tab->access_path()->type == AccessPath::ROWID_INTERSECTION) { - m_ror_intersect = true; - } -#elif defined(FEATURE_X_FOR_MYSQL_26) - if (table->reginfo.qep_tab && table->reginfo.qep_tab->quick() && - table->reginfo.qep_tab->quick()->get_type() == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT) { - m_ror_intersect = true; - } -#endif -} - // @ref set_record_buffer int ha_ctc::set_prefetch_buffer() { if (m_rec_buf) { @@ -3081,7 +2994,6 @@ int ctc_fill_conds(ctc_handler_t m_tch, const Item *pushed_cond, Field **field, memset(m_cond, 0, sizeof(ctc_conds)); Item *items = const_cast(pushed_cond); return dfs_fill_conds(m_tch, items, field, m_cond, no_backslash, NULL); - return dfs_fill_conds(m_tch, items, field, m_cond, no_backslash, NULL); } /** @@ -3110,7 +3022,6 @@ int ha_ctc::rnd_init(bool) { return 0; } - set_ror_intersect(); set_ror_intersect(); ct_errno_t ret = (ct_errno_t)set_prefetch_buffer(); if (ret != CT_SUCCESS) { @@ -3549,7 +3460,6 @@ int ha_ctc::index_init(uint index, bool sorted) { DBUG_TRACE; BEGIN_RECORD_STATS set_ror_intersect(); - set_ror_intersect(); ct_errno_t ret = (ct_errno_t)set_prefetch_buffer(); if (ret != CT_SUCCESS) { return ret; @@ -3592,11 +3502,6 @@ int ha_ctc::cmp_ref(const uchar *ref1, const uchar *ref2) const { return ctc_cmp_cantian_rowid((const rowid_t *)ref1, (const rowid_t *)ref2); } -int ha_ctc::cmp_ref(const uchar *ref1, const uchar *ref2) const { - DBUG_TRACE; - return ctc_cmp_cantian_rowid((const rowid_t *)ref1, (const rowid_t *)ref2); -} - int ha_ctc::process_cantian_record(uchar *buf, record_info_t *record_info, ct_errno_t ct_ret, int rc_ret) { int ret = CT_SUCCESS; check_error_code_to_mysql(ha_thd(), &ct_ret); @@ -3629,7 +3534,6 @@ EXTER_ATTACK int ha_ctc::index_read(uchar *buf, const uchar *key, uint key_len, reset_rec_buf(); } - m_is_covering_index = m_ror_intersect ? false : m_is_covering_index; m_is_covering_index = m_ror_intersect ? false : m_is_covering_index; m_action = m_is_covering_index ? EXP_CURSOR_ACTION_INDEX_ONLY : EXP_CURSOR_ACTION_SELECT; if (m_select_lock == lock_mode::EXCLUSIVE_LOCK) { @@ -3686,13 +3590,11 @@ EXTER_ATTACK int ha_ctc::index_read(uchar *buf, const uchar *key, uint key_len, update_member_tch(m_tch, ctc_hton, ha_thd()); record_info_t record_info = {m_read_buf, 0, nullptr, nullptr}; - attachable_trx_update_pre_addr(ha_thd(), &m_tch, true); attachable_trx_update_pre_addr(ha_thd(), &m_tch, true); ct_errno_t ct_ret = (ct_errno_t)ctc_index_read(&m_tch, &record_info, &index_key_info, get_select_mode(), m_cond, m_is_replace || m_is_insert_dup); update_sess_ctx_by_tch(m_tch, ctc_hton, ha_thd()); attachable_trx_update_pre_addr(ha_thd(), &m_tch, false); - attachable_trx_update_pre_addr(ha_thd(), &m_tch, false); if (index_key_info.need_init) { if (!(table_share->tmp_table != NO_TMP_TABLE && table_share->tmp_table != TRANSACTIONAL_TMP_TABLE)) { update_sess_ctx_cursor_by_tch(m_tch, ctc_hton, ha_thd()); @@ -3720,7 +3622,6 @@ int ha_ctc::index_fetch(uchar *buf) { CTC_RETURN_IF_NOT_ZERO(ctc_alloc_ctc_buf_4_read()); record_info_t record_info = {m_read_buf, 0, nullptr, nullptr}; attachable_trx_update_pre_addr(ha_thd(), &m_tch, true); - attachable_trx_update_pre_addr(ha_thd(), &m_tch, true); ct_ret = (ct_errno_t)ctc_general_fetch(&m_tch, &record_info); attachable_trx_update_pre_addr(ha_thd(), &m_tch, false); attachable_trx_update_pre_addr(ha_thd(), &m_tch, false); @@ -3753,7 +3654,6 @@ int ha_ctc::index_fetch(uchar *buf) { } } - attachable_trx_update_pre_addr(ha_thd(), &m_tch, true); attachable_trx_update_pre_addr(ha_thd(), &m_tch, true); mysql_ret = prefetch_and_fill_record_buffer(buf, ctc_general_prefetch); attachable_trx_update_pre_addr(ha_thd(), &m_tch, false); @@ -3809,8 +3709,6 @@ int ha_ctc::index_first(uchar *buf) { ha_statistic_increment(&System_status_var::ha_read_first_count); m_tch.cursor_addr = INVALID_VALUE64; m_tch.cursor_valid = false; - m_tch.cursor_addr = INVALID_VALUE64; - m_tch.cursor_valid = false; int error = index_read(buf, nullptr, 0, HA_READ_AFTER_KEY); /* MySQL does not seem to allow this to return HA_ERR_KEY_NOT_FOUND */ if (error == HA_ERR_KEY_NOT_FOUND) { @@ -4157,26 +4055,6 @@ void ctc_get_sample_size_value() { } } -/** - * Retrieves and validates the statistics sample size system variable from Cantian. - * - * This function: - * 1. Gets the sample size value from Cantian engine via ctc_get_sample_size_value() - * 2. Validates that the value falls within acceptable range [CTC_MIN_SAMPLE_SIZE, CTC_MAX_SAMPLE_SIZE] - * 3. If valid, updates the global ctc_sample_size variable used for statistics sampling - * - * The sample size determines how much data is sampled when gathering table statistics. - * Invalid values are silently ignored, leaving ctc_sample_size unchanged. - */ -void ctc_get_sample_size_value() { - uint32_t sample_size = 0; - if (ctc_get_sample_size(&sample_size) == CT_SUCCESS) { - if (sample_size >= CTC_MIN_SAMPLE_SIZE && sample_size <= CTC_MAX_SAMPLE_SIZE) { - ctc_sample_size = sample_size; - } - } -} - int32_t ctc_get_cluster_role() { /* Normally, the cluster type should only be PRIMARY or STANDBY */ if (ctc_cluster_role == (int32_t)dis_cluster_role::PRIMARY || @@ -4879,48 +4757,11 @@ int ha_ctc_parallel_read_end_data_fetch(parallel_read_end_data_fetch_ctx_t &end_ } #endif -#if FEATURE_FOR_EVERSQL -int ha_ctc_parallel_read_create_data_fetcher(parallel_read_create_data_fetcher_ctx_t &data_fetcher_ctx, - void *&data_fetcher) { - UNUSED_PARAM(data_fetcher_ctx); - UNUSED_PARAM(data_fetcher); - return 0; -} - -int ha_ctc_parallel_read_destory_data_fetcher(void *&data_fetcher) { - UNUSED_PARAM(data_fetcher); - return 0; -} - -int ha_ctc_parallel_read_start_data_fetch(parallel_read_start_data_fetch_ctx_t &start_data_fetch_ctx) { - UNUSED_PARAM(start_data_fetch_ctx); - return 0; -} - -int ha_ctc_parallel_read_init_data_fetcher(parallel_read_init_data_fetcher_ctx_t &init_data_fetcher_ctx) { - UNUSED_PARAM(init_data_fetcher_ctx); - return 0; -} - -int ha_ctc_parallel_read_add_target_to_data_fetcher( - parallel_read_add_target_to_data_fetcher_ctx_t &target_to_data_fetcher_ctx) { - UNUSED_PARAM(target_to_data_fetcher_ctx); - return 0; -} - -int ha_ctc_parallel_read_end_data_fetch(parallel_read_end_data_fetch_ctx_t &end_data_fetch_ctx) { - UNUSED_PARAM(end_data_fetch_ctx); - return 0; -} -#endif - extern int (*ctc_init)(); extern int (*ctc_deinit)(); int ctc_push_to_engine(THD *thd, AccessPath *root_path, JOIN *); -int ctc_push_to_engine(THD *thd, AccessPath *root_path, JOIN *); - static int ctc_init_func(void *p) { DBUG_TRACE; ctc_hton = (handlerton *)p; @@ -4961,16 +4802,6 @@ static int ctc_init_func(void *p) { ctc_hton->push_to_engine = ctc_push_to_engine; #endif -#ifdef FEATURE_X_FOR_EVERSQL - ctc_hton->data_fetcher_interface.parallel_read_create_data_fetcher = ha_ctc_parallel_read_create_data_fetcher; - ctc_hton->data_fetcher_interface.parallel_read_destory_data_fetcher = ha_ctc_parallel_read_destory_data_fetcher; - ctc_hton->data_fetcher_interface.parallel_read_start_data_fetch = ha_ctc_parallel_read_start_data_fetch; - ctc_hton->data_fetcher_interface.parallel_read_init_data_fetcher = ha_ctc_parallel_read_init_data_fetcher; - ctc_hton->data_fetcher_interface.parallel_read_add_target_to_data_fetcher = - ha_ctc_parallel_read_add_target_to_data_fetcher; - ctc_hton->data_fetcher_interface.parallel_read_end_data_fetch = ha_ctc_parallel_read_end_data_fetch; -#endif - #ifdef FEATURE_X_FOR_EVERSQL ctc_hton->data_fetcher_interface.parallel_read_create_data_fetcher = ha_ctc_parallel_read_create_data_fetcher; ctc_hton->data_fetcher_interface.parallel_read_destory_data_fetcher = ha_ctc_parallel_read_destory_data_fetcher; @@ -5008,9 +4839,6 @@ static int ctc_init_func(void *p) { } ctc_get_cluster_role(); - ctc_get_sample_size_value(); - - ctc_get_sample_size_value(); ctc_log_system("[CTC_INIT]:SUCCESS!"); -- Gitee From cee8a423b55fa983ebd8da48b0f679b0f3ccd31d Mon Sep 17 00:00:00 2001 From: tolyrria <2292493757@qq.com> Date: Tue, 24 Dec 2024 15:58:11 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E5=90=88=E5=B9=B6=E5=86=B2=E7=AA=81?= =?UTF-8?q?=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- storage/ctc/ha_ctc.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/storage/ctc/ha_ctc.cc b/storage/ctc/ha_ctc.cc index ab92ca6..341e0eb 100644 --- a/storage/ctc/ha_ctc.cc +++ b/storage/ctc/ha_ctc.cc @@ -3624,7 +3624,6 @@ int ha_ctc::index_fetch(uchar *buf) { attachable_trx_update_pre_addr(ha_thd(), &m_tch, true); ct_ret = (ct_errno_t)ctc_general_fetch(&m_tch, &record_info); attachable_trx_update_pre_addr(ha_thd(), &m_tch, false); - attachable_trx_update_pre_addr(ha_thd(), &m_tch, false); ret = process_cantian_record(buf, &record_info, ct_ret, HA_ERR_END_OF_FILE); END_RECORD_STATS(EVENT_TYPE_INDEX_FETCH) return ret; @@ -3657,7 +3656,6 @@ int ha_ctc::index_fetch(uchar *buf) { attachable_trx_update_pre_addr(ha_thd(), &m_tch, true); mysql_ret = prefetch_and_fill_record_buffer(buf, ctc_general_prefetch); attachable_trx_update_pre_addr(ha_thd(), &m_tch, false); - attachable_trx_update_pre_addr(ha_thd(), &m_tch, false); if (mysql_ret != 0) { set_my_errno(mysql_ret); -- Gitee From 09b08bdd35bd49cff95bc57b05806ed3171993c6 Mon Sep 17 00:00:00 2001 From: tolyrria <2292493757@qq.com> Date: Tue, 24 Dec 2024 21:33:56 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E8=AF=BBdebug=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- storage/ctc/ha_ctc.cc | 44 +++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/storage/ctc/ha_ctc.cc b/storage/ctc/ha_ctc.cc index 341e0eb..8fc41a6 100644 --- a/storage/ctc/ha_ctc.cc +++ b/storage/ctc/ha_ctc.cc @@ -1477,17 +1477,31 @@ static void ctc_free_cursors_no_autocommit(THD *thd, ctc_handler_t *tch, thd_ses ctc_free_buf(tch, (uint8_t *)cursors); } -bool is_dml_sql_cmd(enum_sql_command sql_cmd) { +// bool is_dml_sql_cmd(enum_sql_command sql_cmd) { - if (sql_cmd == SQLCOM_SELECT || sql_cmd == SQLCOM_UPDATE || - sql_cmd == SQLCOM_INSERT || sql_cmd == SQLCOM_INSERT_SELECT || - sql_cmd == SQLCOM_DELETE || sql_cmd == SQLCOM_REPLACE || - sql_cmd == SQLCOM_REPLACE_SELECT || sql_cmd == SQLCOM_DO - ) { - return true; - } +// if (sql_cmd == SQLCOM_SELECT || sql_cmd == SQLCOM_UPDATE || +// sql_cmd == SQLCOM_INSERT || sql_cmd == SQLCOM_INSERT_SELECT || +// sql_cmd == SQLCOM_DELETE || sql_cmd == SQLCOM_REPLACE || +// sql_cmd == SQLCOM_REPLACE_SELECT || sql_cmd == SQLCOM_DO +// ) { +// return true; +// } - return false; +// return false; +// } + +bool isDMLCommand(const String& sql) { + if (sql.length() < 6) { + return false; + } + String prefix(sql.ptr(), 6, sql.charset()); + for (size_t i = 0; i < 6; ++i) { + prefix[i] = tolower(prefix[i]); + } + return strncmp(prefix.ptr(), "select", 6) == 0 || + strncmp(prefix.ptr(), "insert", 6) == 0 || + strncmp(prefix.ptr(), "delete", 6) == 0 || + strncmp(prefix.ptr(), "update", 6) == 0; } /** @@ -1515,7 +1529,13 @@ static int ctc_commit(handlerton *hton, THD *thd, bool commit_trx) { ct_errno_t ret = CT_SUCCESS; thd_sess_ctx_s *sess_ctx = (thd_sess_ctx_s *)thd_get_ha_data(thd, hton); assert(sess_ctx != nullptr); - bool is_dmlsql = is_dml_sql_cmd(thd->lex->sql_command); + // bool is_dmlsql = is_dml_sql_cmd(thd->lex->sql_command); + bool is_dmlsql = false; + if (thd->query().str != NULL && thd->query().length > 0) { + string dml_sql = string(thd->query().str).substr(0, thd->query().length); + String dml_sql_string(dml_sql.c_str(), dml_sql.length(), thd->charset()); + is_dmlsql = isDMLCommand(dml_sql_string); + } if (will_commit) { commit_preprocess(thd, &tch); attachable_trx_update_pre_addr(thd, &tch, true); @@ -1531,7 +1551,7 @@ static int ctc_commit(handlerton *hton, THD *thd, bool commit_trx) { assert((total_csize == 0) ^ (cursors != nullptr)); ctc_copy_cursors_to_free(sess_ctx, cursors, 0); char sql_str[MAX_DML_SQL_LEN] = ""; - if (is_dmlsql && thd->query().str != NULL && thd->query().length > 0 && enable_stat) { + if (is_dmlsql && enable_stat) { strncpy(sql_str, thd->query().str, MAX_DML_SQL_LEN - 1); } ret = (ct_errno_t)ctc_trx_commit(&tch, cursors, total_csize, &is_ddl_commit, sql_str); @@ -1560,7 +1580,7 @@ static int ctc_commit(handlerton *hton, THD *thd, bool commit_trx) { sess_ctx->is_ctc_trx_begin = 0; } else { char sql_str[MAX_DML_SQL_LEN] = ""; - if (is_dmlsql && thd->query().str != NULL && thd->query().length > 0 && enable_stat) { + if (is_dmlsql && enable_stat) { strncpy(sql_str, thd->query().str, MAX_DML_SQL_LEN - 1); ret = (ct_errno_t)ctc_statistic_commit(&tch,sql_str); if (ret != CT_SUCCESS) { -- Gitee