MXS-1625 Move handle_multi_temp_and_load to QueryClasifier

This commit is contained in:
Johan Wikman
2018-04-09 14:36:48 +03:00
parent 369029b612
commit 42e72bfb81
3 changed files with 87 additions and 94 deletions

View File

@ -211,6 +211,12 @@ public:
bool check_for_multi_stmt(GWBUF *buf, uint8_t packet_type);
current_target_t
handle_multi_temp_and_load(QueryClassifier::current_target_t current_target,
GWBUF *querybuf,
uint8_t packet_type,
uint32_t *qtype);
private:
class PSManager;
typedef std::shared_ptr<PSManager> SPSManager;

View File

@ -47,6 +47,16 @@ bool have_semicolon(const char* ptr, int len)
return false;
}
bool is_packet_a_query(int packet_type)
{
return (packet_type == MXS_COM_QUERY);
}
bool check_for_sp_call(GWBUF *buf, uint8_t packet_type)
{
return packet_type == MXS_COM_QUERY && qc_get_operation(buf) == QUERY_OP_CALL;
}
bool are_multi_statements_allowed(MXS_SESSION* pSession)
{
MySQLProtocol* pPcol = static_cast<MySQLProtocol*>(pSession->client_dcb->protocol);
@ -735,6 +745,75 @@ bool QueryClassifier::check_for_multi_stmt(GWBUF *buf, uint8_t packet_type)
return rval;
}
/**
* @brief Handle multi statement queries and load statements
*
* One of the possible types of handling required when a request is routed
*
* @param qc The query classifier
* @param current_target The current target
* @param querybuf Buffer containing query to be routed
* @param packet_type Type of packet (database specific)
* @param qtype Query type
*
* @return QueryClassifier::CURRENT_TARGET_MASTER if the session should be fixed
* to the master, QueryClassifier::CURRENT_TARGET_UNDEFINED otherwise.
*/
QueryClassifier::current_target_t
QueryClassifier::handle_multi_temp_and_load(QueryClassifier::current_target_t current_target,
GWBUF *querybuf,
uint8_t packet_type,
uint32_t *qtype)
{
QueryClassifier::current_target_t rv = QueryClassifier::CURRENT_TARGET_UNDEFINED;
/** Check for multi-statement queries. If no master server is available
* and a multi-statement is issued, an error is returned to the client
* when the query is routed. */
if ((current_target != QueryClassifier::CURRENT_TARGET_MASTER) &&
(check_for_multi_stmt(querybuf, packet_type) ||
check_for_sp_call(querybuf, packet_type)))
{
MXS_INFO("Multi-statement query or stored procedure call, routing "
"all future queries to master.");
rv = QueryClassifier::CURRENT_TARGET_MASTER;
}
/**
* Check if the query has anything to do with temporary tables.
*/
if (have_tmp_tables() && is_packet_a_query(packet_type))
{
check_drop_tmp_table(querybuf);
if (is_read_tmp_table(querybuf, *qtype))
{
*qtype |= QUERY_TYPE_MASTER_READ;
}
}
check_create_tmp_table(querybuf, *qtype);
/**
* Check if this is a LOAD DATA LOCAL INFILE query. If so, send all queries
* to the master until the last, empty packet arrives.
*/
if (load_data_state() == QueryClassifier::LOAD_DATA_ACTIVE)
{
append_load_data_sent(querybuf);
}
else if (is_packet_a_query(packet_type))
{
qc_query_op_t queryop = qc_get_operation(querybuf);
if (queryop == QUERY_OP_LOAD)
{
set_load_data_state(QueryClassifier::LOAD_DATA_START);
reset_load_data_sent();
}
}
return rv;
}
}

View File

@ -23,97 +23,6 @@ using mxs::QueryClassifier;
namespace
{
/**
* @brief Determine if a packet contains a SQL query
*
* Packet type tells us this, but in a DB specific way. This function is
* provided so that code that is not DB specific can find out whether a packet
* contains a SQL query. Clearly, to be effective different functions must be
* called for different DB types.
*
* @param packet_type Type of packet (integer)
* @return bool indicating whether packet contains a SQL query
*/
bool is_packet_a_query(int packet_type)
{
return (packet_type == MXS_COM_QUERY);
}
bool check_for_sp_call(GWBUF *buf, uint8_t packet_type)
{
return packet_type == MXS_COM_QUERY && qc_get_operation(buf) == QUERY_OP_CALL;
}
/**
* @brief Handle multi statement queries and load statements
*
* One of the possible types of handling required when a request is routed
*
* @param qc The query classifier
* @param current_target The current target
* @param querybuf Buffer containing query to be routed
* @param packet_type Type of packet (database specific)
* @param qtype Query type
*
* @return QueryClassifier::CURRENT_TARGET_MASTER if the session should be fixed
* to the master, QueryClassifier::CURRENT_TARGET_UNDEFINED otherwise.
*/
QueryClassifier::current_target_t
handle_multi_temp_and_load(QueryClassifier& qc,
QueryClassifier::current_target_t current_target,
GWBUF *querybuf,
uint8_t packet_type,
uint32_t *qtype)
{
QueryClassifier::current_target_t rv = QueryClassifier::CURRENT_TARGET_UNDEFINED;
/** Check for multi-statement queries. If no master server is available
* and a multi-statement is issued, an error is returned to the client
* when the query is routed. */
if ((current_target != QueryClassifier::CURRENT_TARGET_MASTER) &&
(qc.check_for_multi_stmt(querybuf, packet_type) ||
check_for_sp_call(querybuf, packet_type)))
{
MXS_INFO("Multi-statement query or stored procedure call, routing "
"all future queries to master.");
rv = QueryClassifier::CURRENT_TARGET_MASTER;
}
/**
* Check if the query has anything to do with temporary tables.
*/
if (qc.have_tmp_tables() && is_packet_a_query(packet_type))
{
qc.check_drop_tmp_table(querybuf);
if (qc.is_read_tmp_table(querybuf, *qtype))
{
*qtype |= QUERY_TYPE_MASTER_READ;
}
}
qc.check_create_tmp_table(querybuf, *qtype);
/**
* Check if this is a LOAD DATA LOCAL INFILE query. If so, send all queries
* to the master until the last, empty packet arrives.
*/
if (qc.load_data_state() == QueryClassifier::LOAD_DATA_ACTIVE)
{
qc.append_load_data_sent(querybuf);
}
else if (is_packet_a_query(packet_type))
{
qc_query_op_t queryop = qc_get_operation(querybuf);
if (queryop == QUERY_OP_LOAD)
{
qc.set_load_data_state(QueryClassifier::LOAD_DATA_START);
qc.reset_load_data_sent();
}
}
return rv;
}
/**
* @brief Get the routing requirements for a query
*
@ -158,9 +67,8 @@ route_target_t get_target_type(QueryClassifier& qc,
{
*type = QueryClassifier::determine_query_type(buffer, *command);
current_target = handle_multi_temp_and_load(qc,
current_target,
buffer, *command, type);
current_target = qc.handle_multi_temp_and_load(current_target,
buffer, *command, type);
if (current_target == QueryClassifier::CURRENT_TARGET_MASTER)
{