diff --git a/server/modules/routing/readwritesplit/rwsplit_tmp_table_multi.cc b/server/modules/routing/readwritesplit/rwsplit_tmp_table_multi.cc index 25b7b5dfa..1dddd5673 100644 --- a/server/modules/routing/readwritesplit/rwsplit_tmp_table_multi.cc +++ b/server/modules/routing/readwritesplit/rwsplit_tmp_table_multi.cc @@ -35,6 +35,68 @@ * somewhere else, outside this router. Perhaps in the query classifier? */ +/** + * @brief Map a function over the list of tables in the query + * + * @param rses Router client session + * @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(RWSplitSession* rses, GWBUF* querybuf, bool (*func)(RWSplitSession*, + 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(rses->client_dcb->session); + std::string table; + + if (strchr(tables[i], '.') == NULL) + { + table += db; + table += "."; + } + + table += tables[i]; + + if (!func(rses, table)) + { + rval = false; + break; + } + } + + return rval; +} + +/** + * Delete callback for foreach_table + */ +bool delete_table(RWSplitSession *rses, const std::string& table) +{ + rses->temp_tables.erase(table); + return true; +} + +/** + * Find callback for foreach_table + */ +bool find_table(RWSplitSession* rses, const std::string& table) +{ + if (rses->temp_tables.find(table) != rses->temp_tables.end()) + { + MXS_INFO("Query targets a temporary table: %s", table.c_str()); + return false; + } + + return true; +} + /** * @brief Check for dropping of temporary tables * @@ -44,27 +106,11 @@ * @param querybuf GWBUF containing the query * @param type The type of the query resolved so far */ -void check_drop_tmp_table(RWSplitSession *router_cli_ses, GWBUF *querybuf) +void check_drop_tmp_table(RWSplitSession *rses, GWBUF *querybuf) { if (qc_is_drop_table_query(querybuf)) { - const QC_FIELD_INFO* info; - size_t n_infos; - qc_get_field_info(querybuf, &info, &n_infos); - - for (size_t i = 0; i < n_infos; i++) - { - const char* db = mxs_mysql_get_current_db(router_cli_ses->client_dcb->session); - std::string table = info[i].database ? info[i].database : db; - table += "."; - - if (info[i].table) - { - table += info[i].table; - } - - router_cli_ses->temp_tables.erase(table); - } + foreach_table(rses, querybuf, delete_table); } } @@ -75,41 +121,22 @@ void check_drop_tmp_table(RWSplitSession *router_cli_ses, GWBUF *querybuf) * @param type The type of the query resolved so far * @return The type of the query */ -bool is_read_tmp_table(RWSplitSession *router_cli_ses, +bool is_read_tmp_table(RWSplitSession *rses, GWBUF *querybuf, uint32_t qtype) { - ss_dassert(router_cli_ses && querybuf && router_cli_ses->client_dcb); + ss_dassert(rses && querybuf && rses->client_dcb); bool rval = false; - if (qtype & (QUERY_TYPE_READ | - QUERY_TYPE_LOCAL_READ | - QUERY_TYPE_USERVAR_READ | - QUERY_TYPE_SYSVAR_READ | - QUERY_TYPE_GSYSVAR_READ)) + 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)) { - const QC_FIELD_INFO* info; - size_t n_infos; - qc_get_field_info(querybuf, &info, &n_infos); - - for (size_t i = 0; i < n_infos; i++) + if (!foreach_table(rses, querybuf, find_table)) { - const char* db = mxs_mysql_get_current_db(router_cli_ses->client_dcb->session); - std::string table = info[i].database ? info[i].database : db; - table += "."; - - if (info[i].table) - { - table += info[i].table; - } - - if (router_cli_ses->temp_tables.find(table) != - router_cli_ses->temp_tables.end()) - { - rval = true; - MXS_INFO("Query targets a temporary table: %s", table.c_str()); - break; - } + rval = true; } } @@ -137,7 +164,7 @@ void check_create_tmp_table(RWSplitSession *router_cli_ses, char* tblname = qc_get_created_table_name(querybuf); std::string table; - if (tblname && *tblname) + if (tblname && *tblname && strchr(tblname, '.') == NULL) { const char* db = mxs_mysql_get_current_db(router_cli_ses->client_dcb->session); table += db;