@ -3,6 +3,7 @@
# include "MySQL_Thread.h"
# include "MySQL_Session.h"
# include "MySQL_Data_Stream.h"
# include "MySQL_Query_Processor.h"
# include "MySQL_Protocol.h"
# include "MySQL_Variables.h"
# include "MySQLFFTO.hpp"
@ -13,9 +14,9 @@
# include "c_tokenizer.h"
# include <iostream>
# include <cstring>
# include <algorithm> // For std::min
# include <algorithm>
extern MySQL_Query_Processor* GloMyQPro ;
extern class MySQL_Query_Processor* GloMyQPro ;
// Helper to read MySQL length-encoded integers
static uint64_t read_lenenc_int ( const unsigned char * & buf , size_t & len ) {
@ -28,19 +29,19 @@ static uint64_t read_lenenc_int(const unsigned char* &buf, size_t &len) {
if ( first_byte < 0xFB ) {
return first_byte ;
} else if ( first_byte = = 0xFC ) {
if ( len < 2 ) return 0 ; // Not enough data
if ( len < 2 ) return 0 ;
uint64_t value = buf [ 0 ] | ( static_cast < uint64_t > ( buf [ 1 ] ) < < 8 ) ;
buf + = 2 ;
len - = 2 ;
return value ;
} else if ( first_byte = = 0xFD ) {
if ( len < 3 ) return 0 ; // Not enough data
if ( len < 3 ) return 0 ;
uint64_t value = buf [ 0 ] | ( static_cast < uint64_t > ( buf [ 1 ] ) < < 8 ) | ( static_cast < uint64_t > ( buf [ 2 ] ) < < 16 ) ;
buf + = 3 ;
len - = 3 ;
return value ;
} else if ( first_byte = = 0xFE ) {
if ( len < 8 ) return 0 ; // Not enough data
if ( len < 8 ) return 0 ;
uint64_t value = buf [ 0 ] | ( static_cast < uint64_t > ( buf [ 1 ] ) < < 8 ) | ( static_cast < uint64_t > ( buf [ 2 ] ) < < 16 ) |
( static_cast < uint64_t > ( buf [ 3 ] ) < < 24 ) | ( static_cast < uint64_t > ( buf [ 4 ] ) < < 32 ) |
( static_cast < uint64_t > ( buf [ 5 ] ) < < 40 ) | ( static_cast < uint64_t > ( buf [ 6 ] ) < < 48 ) |
@ -49,7 +50,7 @@ static uint64_t read_lenenc_int(const unsigned char* &buf, size_t &len) {
len - = 8 ;
return value ;
}
return 0 ; // 0xFB is NULL, which we'll treat as 0 for affected_rows
return 0 ;
}
MySQLFFTO : : MySQLFFTO ( MySQL_Session * session )
@ -114,7 +115,7 @@ void MySQLFFTO::process_client_packet(const unsigned char* data, size_t len) {
} else if ( command = = _MYSQL_COM_STMT_EXECUTE ) {
if ( len > = 5 ) {
uint32_t stmt_id ;
memcpy ( & stmt_id , data + 1 , 4 ) ; // Little-endian stmt_id
memcpy ( & stmt_id , data + 1 , 4 ) ;
auto it = m_statements . find ( stmt_id ) ;
if ( it ! = m_statements . end ( ) ) {
m_current_query = it - > second ;
@ -132,37 +133,27 @@ void MySQLFFTO::process_server_packet(const unsigned char* data, size_t len) {
uint8_t first_byte = data [ 0 ] ;
if ( m_state = = AWAITING_PREPARE_OK ) {
if ( first_byte = = 0x00 & & len > = 5 ) { // COM_STMT_PREPARE_OK
if ( first_byte = = 0x00 & & len > = 5 ) {
uint32_t stmt_id ;
memcpy ( & stmt_id , data + 1 , 4 ) ;
m_statements [ stmt_id ] = m_pending_prepare_query ;
m_state = IDLE ;
} else if ( first_byte = = 0xFF ) { // ERR
} else if ( first_byte = = 0xFF ) {
m_state = IDLE ;
}
} else if ( m_state = = AWAITING_RESULTSET | | m_state = = READING_RESULTSET ) {
if ( first_byte = = 0x00 ) { // OK_Packet
const unsigned char * pos = data + 1 ; // Skip OK byte
if ( first_byte = = 0x00 ) {
const unsigned char * pos = data + 1 ;
size_t remaining_len = len - 1 ;
uint64_t affected_rows = read_lenenc_int ( pos , remaining_len ) ;
uint64_t last_insert_id = read_lenenc_int ( pos , remaining_len ) ; // We don't use this but consume it
unsigned long long duration = monotonic_time ( ) - m_query_start_time ;
report_query_stats ( m_current_query , duration , affected_rows , 0 ) ; // rows_sent is 0 for non-SELECT OK
m_state = IDLE ;
} else if ( first_byte = = 0xFF ) { // ERR_Packet
unsigned long long duration = monotonic_time ( ) - m_query_start_time ;
report_query_stats ( m_current_query , duration ); // No affected_rows/rows_sent for ERR
report_query_stats ( m_current_query , duration , affected_rows , 0 ) ;
m_state = IDLE ;
} else if ( first_byte = = 0xF E & & len < 9 ) { // EOF_Packet (usually end of result set)
} else if ( first_byte = = 0xFF | | ( first_byte = = 0xFE & & len < 9 ) ) {
unsigned long long duration = monotonic_time ( ) - m_query_start_time ;
report_query_stats ( m_current_query , duration ) ; // No affected_rows/rows_sent for EOF
report_query_stats ( m_current_query , duration ) ;
m_state = IDLE ;
} else {
// Assume it's a result set packet (e.g., column definitions or data rows)
// For now, we don't count rows here for simplicity and to maintain "fast forward" philosophy.
// If m_current_query is a SELECT, rows_sent could be counted here.
m_state = READING_RESULTSET ;
}
}
@ -188,7 +179,6 @@ void MySQLFFTO::report_query_stats(const std::string& query, unsigned long long
if ( digest_text ) {
qp . digest_text = digest_text ;
qp . digest = SpookyHash : : Hash64 ( digest_text , strlen ( digest_text ) , 0 ) ;
char * ca = ( char * ) " " ;
if ( mysql_thread___query_digests_track_hostname & & m_session - > client_myds & & m_session - > client_myds - > addr . addr ) {
ca = m_session - > client_myds - > addr . addr ;
@ -206,7 +196,6 @@ void MySQLFFTO::report_query_stats(const std::string& query, unsigned long long
myhash . Final ( & qp . digest_total , & hash2 ) ;
GloMyQPro - > update_query_digest ( qp . digest_total , qp . digest , qp . digest_text , m_session - > current_hostgroup , ui , duration_us , m_session - > thread - > curtime , ca , affected_rows , rows_sent ) ;
free ( digest_text ) ;
}
if ( fst_cmnt ) free ( fst_cmnt ) ;