Merge pull request #5130 from wazir-ahmed/stats-schema

Remove `stats` schema name from the query in stats user session
pull/5168/head
René Cannaò 7 months ago committed by GitHub
commit 562e98d551
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -372,8 +372,6 @@ inline bool get_uint16be(const unsigned char* pkt, uint16_t* dst_p) {
return true;
}
#endif /* __GEN_FUNCTIONS */
bool Proxy_file_exists(const char *);
bool Proxy_file_regular(const char *);
@ -385,7 +383,8 @@ bool mywildcmp(const char *p, const char *str);
std::string trim(const std::string& s);
char* escape_string_single_quotes_and_backslashes(char* input, bool free_it);
const char* escape_string_backslash_spaces(const char* input);
std::string strip_schema_from_query(const char* query, const char* schema,
const std::vector<std::string>& tables = {}, bool ansi_quotes = false);
/**
* @brief Helper function that converts a MYSQL_RES into a 'SQLite3_result'.
* @param resultset The resultset to be converted into a 'SQLite3_result'.
@ -394,3 +393,5 @@ const char* escape_string_backslash_spaces(const char* input);
std::unique_ptr<SQLite3_result> get_SQLite3_resulset(MYSQL_RES* resultset);
std::vector<std::string> split_string(const std::string& str, char delimiter);
#endif /* __GEN_FUNCTIONS */

@ -4030,9 +4030,14 @@ __run_query:
if (needs_vacuum) {
SPA->vacuum_stats(true);
}
} else {
} else { // PROXYSQL_SESSION_STATS
SPA->statsdb->execute("PRAGMA query_only = ON");
SPA->statsdb->execute_statement(query, &error , &cols , &affected_rows , &resultset);
std::string q = strip_schema_from_query(query, "stats");
l_free(query_length, query);
query = l_strdup(q.c_str());
query_length = strlen(query) + 1;
proxy_debug(PROXY_DEBUG_ADMIN, 4, "\nExecuting %s command in stats user session\n\n", query);
SPA->statsdb->execute_statement(query, &error, &cols, &affected_rows, &resultset);
SPA->statsdb->execute("PRAGMA query_only = OFF");
if (needs_vacuum) {
SPA->vacuum_stats(false);

@ -350,3 +350,214 @@ const char* escape_string_backslash_spaces(const char* input) {
*(p++) = '\0';
return output;
}
/**
* Strip schema prefix from the query
*
* @param query The input query
* @param schema The schema name to strip (e.g., "stats")
* @param tables List of table names to process (empty = process all tables)
* @param ansi_quotes If true, double quotes are identifiers (ANSI SQL mode)
* If false, double quotes are string literals (default MySQL mode)
* @return Result string with prefix stripped
*/
std::string strip_schema_from_query(const char* query, const char* schema,
const std::vector<std::string>& tables, bool ansi_quotes) {
if (!query || strlen(query) == 0) {
return "";
}
int query_len = strlen(query);
int schema_len = strlen(schema);
if (schema_len == 0) {
return std::string(query, query_len);
}
if (!strcasestr(query, schema)) {
return std::string(query, query_len);
}
// find string literal positions
std::vector<bool> is_string_char(query_len, false);
bool in_string = false;
char string_delimiter = '\0';
for (int i = 0; i < query_len; i++) {
if (!in_string) {
if (query[i] == '\'' || (!ansi_quotes && query[i] == '"')) {
in_string = true;
string_delimiter = query[i];
is_string_char[i] = true;
}
} else {
is_string_char[i] = true;
if (query[i] == string_delimiter) {
if (i + 1 < query_len && query[i + 1] == string_delimiter) {
i++; // Skip escaped quote
is_string_char[i] = true;
} else {
in_string = false;
}
}
}
}
// scan query string and look for the pattern <schema>.<table>
struct SchemaTablePos {
int schema_start;
int schema_end;
int table_start;
int table_end;
};
std::vector<SchemaTablePos> matches;
const char* search = query;
const char* found = nullptr;
while ((found = strcasestr(search, schema)) != nullptr) {
int schema_pos = found - query;
if (is_string_char[schema_pos]) {
// schema name is part of string literal; skip this match
search = found + schema_len;
continue;
}
if (schema_pos > 0) {
char prev = query[schema_pos - 1];
if (std::isalnum(prev) || prev == '_') {
// schema name is a substring; skip this match
search = found + schema_len;
continue;
}
}
int start = schema_pos;
int pos = schema_pos + schema_len;
char schema_quote = '\0';
// check if schema is quoted
if (schema_pos > 0 && (query[schema_pos - 1] == '`' ||
(ansi_quotes && query[schema_pos - 1] == '"'))) {
schema_quote = query[schema_pos - 1];
start--;
// check for closing quote
if (pos < query_len && query[pos] == schema_quote) {
pos++;
} else {
// no closing quote; skip this match
search = query + pos;
continue;
}
}
// match dot character
// skip the whitespaces before dot character
while (pos < query_len && std::isspace(query[pos])) {
pos++;
}
if (pos >= query_len || query[pos] != '.') {
// dot character not found followed by schema name; skip this match
search = query + pos;
continue;
}
pos++;
// skip the whitespaces after dot character
while (pos < query_len && std::isspace(query[pos])) {
pos++;
}
if (pos >= query_len) {
// table name not found followed by dot character; skip this match
search = query + pos;
continue;
}
// extract table name
int table_start = pos;
char table_quote = '\0';
bool table_quoted = false;
if (query[pos] == '`' || (ansi_quotes && query[pos] == '"')) {
table_quoted = true;
table_quote = query[pos];
pos++;
table_start = pos;
}
int table_end = pos;
if (table_quoted) {
while (table_end < query_len && query[table_end] != table_quote) {
table_end++;
}
if (table_end >= query_len) {
// no closing quote for table name; skip this match
search = query + pos;
continue;
}
pos = table_end + 1;
} else {
while (table_end < query_len &&
(std::isalnum(query[table_end]) || query[table_end] == '_')) {
table_end++;
}
pos = table_end;
}
// try matching table name if table_list not empty
if (!tables.empty()) {
int table_name_len = table_end - table_start;
bool table_found = false;
for (auto& target_table : tables) {
if (target_table.length() == (size_t) table_name_len &&
strncasecmp(query + table_start, target_table.c_str(), table_name_len) == 0) {
table_found = true;
break;
}
}
if (!table_found) {
search = query + pos;
continue;
}
}
// add start/end pos to match set
table_start = table_quoted ? table_start - 1 : table_start;
table_end = table_quoted ? table_end + 1 : table_end;
matches.push_back({start, pos, table_start, table_end});
search = query + table_end;
}
if (matches.empty()) {
return std::string(query, query_len);
}
// strip matched schema name and build final result
std::string result;
result.reserve(query_len);
int last_pos = 0;
for (const auto& m : matches) {
// append text before this match
result.append(query + last_pos, m.schema_start - last_pos);
// append just the table name, skip schema name and dot character
result.append(query + m.table_start, m.table_end - m.table_start);
last_pos = m.schema_end;
}
// append remaining query
if (last_pos < query_len) {
result.append(query + last_pos, query_len - last_pos);
}
return result;
}

Loading…
Cancel
Save