From 9a6d66f104803a36bfcf2061b8ece5cef8b42107 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Mon, 9 Apr 2018 14:15:24 +0300 Subject: [PATCH] MXS-1625 Move functions to QueryClassifier --- include/maxscale/queryclassifier.hh | 4 + server/core/queryclassifier.cc | 97 +++++++++++++-- .../routing/readwritesplit/routeinfo.cc | 111 +----------------- 3 files changed, 90 insertions(+), 122 deletions(-) diff --git a/include/maxscale/queryclassifier.hh b/include/maxscale/queryclassifier.hh index 31d7a4a53..335e91d6e 100644 --- a/include/maxscale/queryclassifier.hh +++ b/include/maxscale/queryclassifier.hh @@ -205,6 +205,10 @@ public: void check_create_tmp_table(GWBUF *querybuf, uint32_t type); + bool is_read_tmp_table(GWBUF *querybuf, uint32_t qtype); + + void check_drop_tmp_table(GWBUF *querybuf); + private: class PSManager; typedef std::shared_ptr SPSManager; diff --git a/server/core/queryclassifier.cc b/server/core/queryclassifier.cc index bd96c793d..7a6f042d3 100644 --- a/server/core/queryclassifier.cc +++ b/server/core/queryclassifier.cc @@ -21,9 +21,19 @@ namespace { +using namespace maxscale; + const int QC_TRACE_MSG_LEN = 1000; +// Copied from mysql_common.c +// TODO: The current database should somehow be available in a generic fashion. +const char* qc_mysql_get_current_db(MXS_SESSION* session) +{ + MYSQL_session* data = (MYSQL_session*)session->client_dcb->data; + return data->db; +} + bool are_multi_statements_allowed(MXS_SESSION* pSession) { MySQLProtocol* pPcol = static_cast(pSession->client_dcb->protocol); @@ -97,6 +107,53 @@ void replace_binary_ps_id(GWBUF* buffer, uint32_t id) gw_mysql_set_byte4(ptr, id); } +bool find_table(QueryClassifier& qc, const std::string& table) +{ + if (qc.is_tmp_table(table)) + { + MXS_INFO("Query targets a temporary table: %s", table.c_str()); + return false; + } + + return true; +} + +bool delete_table(QueryClassifier& qc, const std::string& table) +{ + qc.remove_tmp_table(table); + return true; +} + +bool foreach_table(QueryClassifier& qc, GWBUF* querybuf, bool (*func)(QueryClassifier& qc, + const std::string&)) +{ + bool rval = true; + int n_tables; + char** tables = qc_get_table_names(querybuf, &n_tables, true); + + for (int i = 0; i < n_tables; i++) + { + const char* db = qc_mysql_get_current_db(qc.session()); + std::string table; + + if (strchr(tables[i], '.') == NULL) + { + table += db; + table += "."; + } + + table += tables[i]; + + if (!func(qc, table)) + { + rval = false; + break; + } + } + + return rval; +} + } namespace maxscale @@ -571,19 +628,6 @@ uint32_t QueryClassifier::determine_query_type(GWBUF *querybuf, int command) return type; } -namespace -{ - -// Copied from mysql_common.c -// TODO: The current database should somehow be available in a generic fashion. -const char* qc_mysql_get_current_db(MXS_SESSION* session) -{ - MYSQL_session* data = (MYSQL_session*)session->client_dcb->data; - return data->db; -} - -} - void QueryClassifier::check_create_tmp_table(GWBUF *querybuf, uint32_t type) { if (qc_query_is_type(type, QUERY_TYPE_CREATE_TMP_TABLE)) @@ -607,5 +651,32 @@ void QueryClassifier::check_create_tmp_table(GWBUF *querybuf, uint32_t type) } } +bool QueryClassifier::is_read_tmp_table(GWBUF *querybuf, uint32_t qtype) +{ + bool rval = false; + + if (qc_query_is_type(qtype, QUERY_TYPE_READ) || + qc_query_is_type(qtype, QUERY_TYPE_LOCAL_READ) || + qc_query_is_type(qtype, QUERY_TYPE_USERVAR_READ) || + qc_query_is_type(qtype, QUERY_TYPE_SYSVAR_READ) || + qc_query_is_type(qtype, QUERY_TYPE_GSYSVAR_READ)) + { + if (!foreach_table(*this, querybuf, find_table)) + { + rval = true; + } + } + + return rval; +} + +void QueryClassifier::check_drop_tmp_table(GWBUF *querybuf) +{ + if (qc_is_drop_table_query(querybuf)) + { + foreach_table(*this, querybuf, delete_table); + } +} + } diff --git a/server/modules/routing/readwritesplit/routeinfo.cc b/server/modules/routing/readwritesplit/routeinfo.cc index 0649d9be6..96046e1ee 100644 --- a/server/modules/routing/readwritesplit/routeinfo.cc +++ b/server/modules/routing/readwritesplit/routeinfo.cc @@ -23,113 +23,6 @@ using mxs::QueryClassifier; namespace { -/** - * Find callback for foreach_table - */ -bool find_table(QueryClassifier& qc, const std::string& table) -{ - if (qc.is_tmp_table(table)) - { - MXS_INFO("Query targets a temporary table: %s", table.c_str()); - return false; - } - - return true; -} - -/** - * @brief Map a function over the list of tables in the query - * - * @param qc The query classifier. - * @param querybuf The query to inspect - * @param func Callback that is called for each table - * - * @return True if all tables were iterated, false if the iteration was stopped early - */ -static bool foreach_table(QueryClassifier& qc, GWBUF* querybuf, bool (*func)(QueryClassifier& qc, - const std::string&)) -{ - bool rval = true; - int n_tables; - char** tables = qc_get_table_names(querybuf, &n_tables, true); - - for (int i = 0; i < n_tables; i++) - { - const char* db = mxs_mysql_get_current_db(qc.session()); - std::string table; - - if (strchr(tables[i], '.') == NULL) - { - table += db; - table += "."; - } - - table += tables[i]; - - if (!func(qc, table)) - { - rval = false; - break; - } - } - - return rval; -} - -/** - * Check if the query targets a temporary table. - * @param qc The query classifier. - * @param querybuf GWBUF containing the query - * @param type The type of the query resolved so far - * @return The type of the query - */ -bool is_read_tmp_table(QueryClassifier& qc, - GWBUF *querybuf, - uint32_t qtype) -{ - bool rval = false; - - if (qc_query_is_type(qtype, QUERY_TYPE_READ) || - qc_query_is_type(qtype, QUERY_TYPE_LOCAL_READ) || - qc_query_is_type(qtype, QUERY_TYPE_USERVAR_READ) || - qc_query_is_type(qtype, QUERY_TYPE_SYSVAR_READ) || - qc_query_is_type(qtype, QUERY_TYPE_GSYSVAR_READ)) - { - if (!foreach_table(qc, querybuf, find_table)) - { - rval = true; - } - } - - return rval; -} - -/** - * Delete callback for foreach_table - */ -bool delete_table(QueryClassifier& qc, const std::string& table) -{ - qc.remove_tmp_table(table); - return true; -} - -/** - * @brief Check for dropping of temporary tables - * - * Check if the query is a DROP TABLE... query and - * if it targets a temporary table, remove it from the hashtable. - * @param qc The query classifier - * @param querybuf GWBUF containing the query - * @param type The type of the query resolved so far - */ -void check_drop_tmp_table(QueryClassifier& qc, GWBUF *querybuf) -{ - if (qc_is_drop_table_query(querybuf)) - { - foreach_table(qc, querybuf, delete_table); - } -} - /** * @brief Determine if a packet contains a SQL query * @@ -248,8 +141,8 @@ handle_multi_temp_and_load(QueryClassifier& qc, */ if (qc.have_tmp_tables() && is_packet_a_query(packet_type)) { - check_drop_tmp_table(qc, querybuf); - if (is_read_tmp_table(qc, querybuf, *qtype)) + qc.check_drop_tmp_table(querybuf); + if (qc.is_read_tmp_table(querybuf, *qtype)) { *qtype |= QUERY_TYPE_MASTER_READ; }