Fix temporary table detection in readwritesplit
The column information does not contain the used tables and the correct function to use is qc_get_table_names. Added a utility function for iterating over the set of tables. This removes the need to have the same table iteration code in multiple places and makes the code easier to comprehend.
This commit is contained in:
@ -35,6 +35,68 @@
|
|||||||
* somewhere else, outside this router. Perhaps in the query classifier?
|
* 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
|
* @brief Check for dropping of temporary tables
|
||||||
*
|
*
|
||||||
@ -44,27 +106,11 @@
|
|||||||
* @param querybuf GWBUF containing the query
|
* @param querybuf GWBUF containing the query
|
||||||
* @param type The type of the query resolved so far
|
* @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))
|
if (qc_is_drop_table_query(querybuf))
|
||||||
{
|
{
|
||||||
const QC_FIELD_INFO* info;
|
foreach_table(rses, querybuf, delete_table);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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
|
* @param type The type of the query resolved so far
|
||||||
* @return The type of the query
|
* @return The type of the query
|
||||||
*/
|
*/
|
||||||
bool is_read_tmp_table(RWSplitSession *router_cli_ses,
|
bool is_read_tmp_table(RWSplitSession *rses,
|
||||||
GWBUF *querybuf,
|
GWBUF *querybuf,
|
||||||
uint32_t qtype)
|
uint32_t qtype)
|
||||||
{
|
{
|
||||||
ss_dassert(router_cli_ses && querybuf && router_cli_ses->client_dcb);
|
ss_dassert(rses && querybuf && rses->client_dcb);
|
||||||
bool rval = false;
|
bool rval = false;
|
||||||
|
|
||||||
if (qtype & (QUERY_TYPE_READ |
|
if (qc_query_is_type(qtype, QUERY_TYPE_READ) ||
|
||||||
QUERY_TYPE_LOCAL_READ |
|
qc_query_is_type(qtype, QUERY_TYPE_LOCAL_READ) ||
|
||||||
QUERY_TYPE_USERVAR_READ |
|
qc_query_is_type(qtype, QUERY_TYPE_USERVAR_READ) ||
|
||||||
QUERY_TYPE_SYSVAR_READ |
|
qc_query_is_type(qtype, QUERY_TYPE_SYSVAR_READ) ||
|
||||||
QUERY_TYPE_GSYSVAR_READ))
|
qc_query_is_type(qtype, QUERY_TYPE_GSYSVAR_READ))
|
||||||
{
|
{
|
||||||
const QC_FIELD_INFO* info;
|
if (!foreach_table(rses, querybuf, find_table))
|
||||||
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);
|
rval = true;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,7 +164,7 @@ void check_create_tmp_table(RWSplitSession *router_cli_ses,
|
|||||||
char* tblname = qc_get_created_table_name(querybuf);
|
char* tblname = qc_get_created_table_name(querybuf);
|
||||||
std::string table;
|
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);
|
const char* db = mxs_mysql_get_current_db(router_cli_ses->client_dcb->session);
|
||||||
table += db;
|
table += db;
|
||||||
|
Reference in New Issue
Block a user