feat: Add leading comments (--) detection for 'run_sql_readonly'

Read only queries are no longer flagged as non-readonly when starting
with double dash comments.
pull/5331/head
Javier Jaramago Fernández 3 months ago
parent fec97bbabe
commit e351a0df74

@ -285,6 +285,22 @@ public:
int timeout_sec = 2
);
/**
* @brief Strip simple SQL comments from the start of a query
*
* Removes leading '-- ' style comments from SQL queries.
* Handles multiple comment lines and whitespace before/after comments.
* This is a simple pre-processing step to allow queries with leading comments.
*
* @param sql The SQL query that may have leading comments
* @return SQL query with leading comments removed
*
* @note Only removes comments from the START of the query
* @note Does not handle inline comments (comments within the query)
* @note Does not handle block comments
*/
std::string strip_leading_comments(const std::string& sql);
/**
* @brief Explain a query (EXPLAIN/EXPLAIN ANALYZE)
* @param sql SQL query to explain

@ -146,6 +146,22 @@ private:
*/
bool is_dangerous_query(const std::string& query);
/**
* @brief Strip simple SQL comments from the start of a query
*
* Removes leading '-- ' style comments from SQL queries.
* Handles multiple comment lines and whitespace before/after comments.
* This is a simple pre-processing step to allow queries with leading comments.
*
* @param sql The SQL query that may have leading comments
* @return SQL query with leading comments removed
*
* @note Only removes comments from the START of the query
* @note Does not handle inline comments (comments within the query)
* @note Does not handle block comments
*/
std::string strip_leading_comments(const std::string& sql);
// Friend function for tracking tool invocations
friend void track_tool_invocation(Query_Tool_Handler*, const std::string&, const std::string&, const std::string&, unsigned long long);

@ -1049,6 +1049,52 @@ std::string MySQL_Tool_Handler::sample_distinct(
return result.dump();
}
/**
* @brief Strip simple SQL comments from the start of a query
*
* Removes leading '-- ' style comments from SQL queries.
* Handles multiple comment lines and whitespace before/after comments.
* This is a simple pre-processing step to allow queries with leading comments.
*
* @param sql The SQL query that may have leading comments
* @return SQL query with leading comments removed
*
* @note Only removes comments from the START of the query
* @note Does not handle inline comments (comments within the query)
* @note Does not handle \/\* *\/ style comments
*/
std::string MySQL_Tool_Handler::strip_leading_comments(const std::string& sql) {
std::string result = sql;
size_t pos = 0;
size_t len = result.length();
// Skip any leading whitespace
while (pos < len && isspace(result[pos])) {
pos++;
}
// Remove leading '-- ' comment lines
while (pos < len && result.substr(pos, 3) == "-- ") {
// Found a comment, skip to end of line
while (pos < len && result[pos] != '\n') {
pos++;
}
// Skip the newline
if (pos < len && result[pos] == '\n') {
pos++;
}
// Skip any leading whitespace before next comment
while (pos < len && isspace(result[pos])) {
pos++;
}
}
// Return the query without leading comments
return result.substr(pos);
}
std::string MySQL_Tool_Handler::run_sql_readonly(
const std::string& sql,
int max_rows,
@ -1057,14 +1103,16 @@ std::string MySQL_Tool_Handler::run_sql_readonly(
json result;
result["success"] = false;
// Strip leading comments from the query
std::string query = strip_leading_comments(sql);
// Validate query is read-only
if (!validate_readonly_query(sql)) {
if (!validate_readonly_query(query)) {
result["error"] = "Query validation failed: not SELECT-only or contains dangerous keywords";
return result.dump();
}
// Add LIMIT if not present and not an aggregate query
std::string query = sql;
std::string upper = sql;
std::transform(upper.begin(), upper.end(), upper.begin(), ::toupper);

@ -610,6 +610,35 @@ bool Query_Tool_Handler::is_dangerous_query(const std::string& query) {
return false;
}
std::string Query_Tool_Handler::strip_leading_comments(const std::string& sql) {
std::string result = sql;
size_t pos = 0;
size_t len = result.length();
// Skip leading whitespace
while (pos < len && isspace(result[pos])) {
pos++;
}
// Remove leading '-- ' comment lines
while (pos < len && result.substr(pos, 2) == "--") {
// Skip until end of line
while (pos < len && result[pos] != '\n') {
pos++;
}
// Skip the newline
if (pos < len && result[pos] == '\n') {
pos++;
}
// Skip leading whitespace after the comment
while (pos < len && isspace(result[pos])) {
pos++;
}
}
return result.substr(pos);
}
json Query_Tool_Handler::create_tool_schema(
const std::string& tool_name,
const std::string& description,
@ -1749,6 +1778,9 @@ json Query_Tool_Handler::execute_tool(const std::string& tool_name, const json&
delete qpo;
// Strip leading comments from query
sql = strip_leading_comments(sql);
// Continue with validation and execution
if (!validate_readonly_query(sql)) {
result = create_error_response("SQL is not read-only");

Loading…
Cancel
Save