Qt:判断一个sql语句是否是select语句
代码作者:Qwen3-Coder大模型。
#include <QRegularExpression>
#include <QDebug>static QString removeSqlComments(const QString &sql)
{QString result = sql;// 处理单行注释 --QStringList lines = result.split('\n');QStringList processedLines;for (const QString &line : lines) {int commentPos = line.indexOf("--");if (commentPos != -1) {processedLines.append(line.left(commentPos));} else {processedLines.append(line);}}result = processedLines.join('\n');// 处理多行注释 /* */QRegularExpression multiLineComment(R"(/\*.*?\*/)",QRegularExpression::DotMatchesEverythingOption);result.replace(multiLineComment, " ");return result.trimmed();
}static bool isSelectQuery(const QString &sql)
{QString trimmedSql = sql.trimmed();if (trimmedSql.isEmpty()) {return false;}// 移除SQL注释QString cleanSql = removeSqlComments(trimmedSql);QString lowerSql = cleanSql.toLower().trimmed();// 检查是否以非SELECT语句开头static const QStringList nonSelectStarters = {"insert", "update", "delete", "create", "alter", "drop","truncate", "merge", "call", "exec", "begin", "commit","rollback", "set", "use", "grant", "revoke", "show", "describe"};for (const QString &starter : nonSelectStarters) {if (lowerSql.startsWith(starter + " ")) {return false;}}// EXPLAIN特殊处理if (lowerSql.startsWith("explain ")) {QRegularExpression explainSelectRegex(R"(\bexplain\s+select\b)");if (explainSelectRegex.match(lowerSql).hasMatch()) {return false;}}// 查找第一个SELECT的位置QRegularExpression selectRegex(R"(\bselect\b)");QRegularExpressionMatch match = selectRegex.match(lowerSql);if (match.hasMatch()) {int selectPos = match.capturedStart();QString beforeSelect = lowerSql.left(selectPos).trimmed();// 检查SELECT之后的内容QString afterSelect = lowerSql.mid(match.capturedEnd()).trimmed();// 如果SELECT后面没有任何有意义的内容,不算有效查询// 有效内容应该包含字段、FROM子句等if (afterSelect.isEmpty() ||afterSelect.startsWith(";") ||afterSelect.startsWith(")") || // 在子查询中afterSelect.startsWith(",")) { // 在列表中return false;}// 检查SELECT前面是否只有WITH(CTE)if (!beforeSelect.isEmpty() && !beforeSelect.startsWith("with ")) {return false;}return true;}return false;
}void testIsSelectQuery() {struct TestCase {QString sql;bool expected;QString description;};QList<TestCase> testCases = {// 正确的SELECT语句{"SELECT * FROM users;", true, "基本SELECT语句"},{"select * from users;", true, "小写SELECT语句"},{" SELECT * FROM users ;", true, "带多余空格的SELECT"},{"SELECT id, name FROM users WHERE age > 18;", true, "带WHERE的SELECT"},{"SELECT COUNT(*) FROM users GROUP BY department;", true, "带GROUP BY的SELECT"},{"SELECT u.name, p.title FROM users u JOIN posts p ON u.id = p.user_id;", true, "JOIN查询"},{"WITH temp AS (SELECT * FROM users) SELECT * FROM temp;", true, "WITH子句查询"},{"WITH cte AS (SELECT id FROM users) SELECT * FROM cte WHERE id > 10;", true, "复杂CTE查询"},// EXPLAIN相关(根据需求可能需要调整){"EXPLAIN SELECT * FROM users;", false, "EXPLAIN语句(可能不算纯SELECT)"},{"EXPLAIN ANALYZE SELECT * FROM users;", false, "EXPLAIN ANALYZE语句"},// 非SELECT语句{"INSERT INTO users (name) VALUES ('John');", false, "INSERT语句"},{"UPDATE users SET name = 'Jane' WHERE id = 1;", false, "UPDATE语句"},{"DELETE FROM users WHERE id = 1;", false, "DELETE语句"},{"CREATE TABLE users (id INT, name VARCHAR(50));", false, "CREATE语句"},{"ALTER TABLE users ADD COLUMN email VARCHAR(100);", false, "ALTER语句"},{"DROP TABLE users;", false, "DROP语句"},{"CREATE INDEX idx_name ON users(name);", false, "CREATE INDEX语句"},{"TRUNCATE TABLE users;", false, "TRUNCATE语句"},{"MERGE INTO target USING source ON condition;", false, "MERGE语句"},{"CALL stored_procedure();", false, "CALL语句"},// 边界情况{"", false, "空字符串"},{" ", false, "只有空格"},{"SELECT", false, "只有SELECT关键字"},{"SELECT;", false, "SELECT后直接分号"},{"SELECT\n*\nFROM\nusers;", true, "带换行符的SELECT"},{"SELECT\t*\tFROM\tusers;", true, "带制表符的SELECT"},{"-- SELECT * FROM users; \n SELECT * FROM posts;", true, "注释后有SELECT"},{"/* SELECT comment */ SELECT * FROM users;", true, "多行注释后的SELECT"},{"SELECT123 FROM table;", false, "SELECT作为标识符(不是关键字)"},{"SELECTED FROM table;", false, "SELECTED不是SELECT"},// 复杂查询{"SELECT * FROM (SELECT * FROM users) AS subquery;", true, "子查询"},{"SELECT * FROM users UNION SELECT * FROM admins;", true, "UNION查询"},{"SELECT CASE WHEN id > 0 THEN 'positive' ELSE 'negative' END FROM numbers;", true, "CASE语句"},{"SELECT * FROM users ORDER BY name LIMIT 10;", true, "ORDER BY和LIMIT"},// 混合大小写{"Select * From Users;", true, "混合大小写1"},{"SeLeCt * FrOm UsErS;", true, "混合大小写2"},{"SELECT DISTINCT name FROM users;", true, "带DISTINCT的SELECT"},// 包含SELECT但不是SELECT语句{"SELECTED_COLUMNS FROM table;", false, "SELECT作为标识符"},{"SELECT_USER FROM mapping;", false, "SELECT作为标识符"},};qDebug() << "=== 测试 SELECT 查询检测函数 ===";int passed = 0;int total = testCases.size();for (int i = 0; i < testCases.size(); ++i) {const auto& testCase = testCases[i];bool result = isSelectQuery(testCase.sql);bool success = (result == testCase.expected);qDebug() << QString("测试 %1: %2").arg(i + 1, 3).arg(success ? "✓ PASS" : "✗ FAIL");qDebug() << " SQL: " << testCase.sql;qDebug() << " 期望: " << (testCase.expected ? "true" : "false")<< ", 实际: " << (result ? "true" : "false");qDebug() << " 说明: " << testCase.description;if (success) {passed++;} else {qDebug() << " *** 测试失败 ***";}qDebug() << "";}qDebug() << QString("测试结果: %1/%2 通过").arg(passed).arg(total);qDebug() << QString("成功率: %1%").arg((double)passed / total * 100, 0, 'f', 1);
}int main(int argc, char *argv[])
{testIsSelectQuery();return 1;
}