From 2dfd61a9585838061bcb526a4ee62d46f93da2e8 Mon Sep 17 00:00:00 2001 From: Rene Cannao Date: Tue, 20 Jan 2026 21:53:15 +0000 Subject: [PATCH] Replace remaining direct sqlite3_* calls with proxy_sqlite3_* equivalents (address code-review) --- lib/Admin_Bootstrap.cpp | 22 +- lib/Anomaly_Detector.cpp.bak | 953 ++++++++++++++++++++++++++++++++++ lib/Discovery_Schema.cpp | 56 +- lib/PgSQL_Monitor.cpp | 12 +- lib/ProxySQL_Admin_Stats.cpp | 108 ++-- lib/RAG_Tool_Handler.cpp | 14 +- lib/debug.cpp | 2 +- lib/proxy_sqlite3_symbols.cpp | 8 +- lib/sqlite3db.cpp | 2 +- src/SQLite3_Server.cpp | 54 +- 10 files changed, 1092 insertions(+), 139 deletions(-) create mode 100644 lib/Anomaly_Detector.cpp.bak diff --git a/lib/Admin_Bootstrap.cpp b/lib/Admin_Bootstrap.cpp index 60f9458c2..4fed656ac 100644 --- a/lib/Admin_Bootstrap.cpp +++ b/lib/Admin_Bootstrap.cpp @@ -92,8 +92,8 @@ using json = nlohmann::json; * * @see https://github.com/asg017/sqlite-vec for sqlite-vec documentation */ -extern "C" int sqlite3_vec_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi); -extern "C" int sqlite3_rembed_init(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi); +extern "C" int (*proxy_sqlite3_vec_init)(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi); +extern "C" int (*proxy_sqlite3_rembed_init)(sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi); #include "microhttpd.h" #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || defined(__mips__)) && defined(__linux) @@ -572,7 +572,7 @@ bool ProxySQL_Admin::init(const bootstrap_info_t& bootstrap_info) { * SELECT rowid, distance FROM vec_data WHERE vector MATCH json('[0.1, 0.2, ...]'); * @endcode * - * @see sqlite3_vec_init() for extension initialization + * @see (*proxy_sqlite3_vec_init)() for extension initialization * @see deps/sqlite3/README.md for integration documentation * @see https://github.com/asg017/sqlite-vec for sqlite-vec documentation */ @@ -592,7 +592,7 @@ bool ProxySQL_Admin::init(const bootstrap_info_t& bootstrap_info) { * Allows loading SQLite extensions at runtime. This is required for * sqlite-vec to be registered when the database is opened. */ - sqlite3_enable_load_extension(admindb->get_db(),1); + (*proxy_sqlite3_enable_load_extension)(admindb->get_db(),1); /** * @brief Register sqlite-vec extension for auto-loading @@ -609,8 +609,8 @@ bool ProxySQL_Admin::init(const bootstrap_info_t& bootstrap_info) { * @note The sqlite3_vec_init function is cast to a function pointer * for SQLite's auto-extension mechanism. */ - sqlite3_auto_extension( (void(*)(void))sqlite3_vec_init); - sqlite3_auto_extension( (void(*)(void))sqlite3_rembed_init); + (*proxy_sqlite3_auto_extension)( (void(*)(void))sqlite3_vec_init); + (*proxy_sqlite3_auto_extension)( (void(*)(void))sqlite3_rembed_init); /** * @brief Open the stats database with shared cache mode @@ -627,7 +627,7 @@ bool ProxySQL_Admin::init(const bootstrap_info_t& bootstrap_info) { * Allows loading SQLite extensions at runtime. This enables sqlite-vec to be * registered in the stats database for advanced analytics operations. */ - sqlite3_enable_load_extension(statsdb->get_db(),1); + (*proxy_sqlite3_enable_load_extension)(statsdb->get_db(),1); // check if file exists , see #617 bool admindb_file_exists=Proxy_file_exists(GloVars.admindb); @@ -657,7 +657,7 @@ bool ProxySQL_Admin::init(const bootstrap_info_t& bootstrap_info) { * - Configuration optimization with vector-based recommendations * - Intelligent grouping of similar configurations */ - sqlite3_enable_load_extension(configdb->get_db(),1); + (*proxy_sqlite3_enable_load_extension)(configdb->get_db(),1); // Fully synchronous is not required. See to #1055 // https://sqlite.org/pragma.html#pragma_synchronous configdb->execute("PRAGMA synchronous=0"); @@ -682,7 +682,7 @@ bool ProxySQL_Admin::init(const bootstrap_info_t& bootstrap_info) { * - Clustering similar server performance metrics * - Predictive monitoring based on historical vector patterns */ - sqlite3_enable_load_extension(monitordb->get_db(),1); + (*proxy_sqlite3_enable_load_extension)(monitordb->get_db(),1); statsdb_disk = new SQLite3DB(); /** @@ -704,7 +704,7 @@ bool ProxySQL_Admin::init(const bootstrap_info_t& bootstrap_info) { * - Clustering similar query digests for optimization insights * - Long-term performance monitoring with vector-based analytics */ - sqlite3_enable_load_extension(statsdb_disk->get_db(),1); + (*proxy_sqlite3_enable_load_extension)(statsdb_disk->get_db(),1); // char *dbname = (char *)malloc(strlen(GloVars.statsdb_disk)+50); // sprintf(dbname,"%s?mode=memory&cache=shared",GloVars.statsdb_disk); // statsdb_disk->open(dbname, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_FULLMUTEX); @@ -733,7 +733,7 @@ bool ProxySQL_Admin::init(const bootstrap_info_t& bootstrap_info) { * Allows loading SQLite extensions at runtime. This enables sqlite-vec to be * registered for vector similarity searches in the catalog. */ - sqlite3_enable_load_extension(mcpdb->get_db(),1); + (*proxy_sqlite3_enable_load_extension)(mcpdb->get_db(),1); tables_defs_admin=new std::vector; tables_defs_stats=new std::vector; diff --git a/lib/Anomaly_Detector.cpp.bak b/lib/Anomaly_Detector.cpp.bak new file mode 100644 index 000000000..46c949126 --- /dev/null +++ b/lib/Anomaly_Detector.cpp.bak @@ -0,0 +1,953 @@ +/** + * @file Anomaly_Detector.cpp + * @brief Implementation of Real-time Anomaly Detection for ProxySQL + * + * Implements multi-stage anomaly detection pipeline: + * 1. SQL Injection Pattern Detection + * 2. Query Normalization and Pattern Matching + * 3. Rate Limiting per User/Host + * 4. Statistical Outlier Detection + * 5. Embedding-based Threat Similarity + * + * @see Anomaly_Detector.h + */ + +#include "Anomaly_Detector.h" +#include "sqlite3db.h" +#include "proxysql_utils.h" +#include "GenAI_Thread.h" +#include "cpp.h" +#include +#include +#include +#include +#include +#include +#include + +// JSON library +#include "../deps/json/json.hpp" +using json = nlohmann::json; +#define PROXYJSON + +// Global GenAI handler for embedding generation +extern GenAI_Threads_Handler *GloGATH; + +// ============================================================================ +// Constants +// ============================================================================ + +// SQL Injection Patterns (regex-based) +static const char* SQL_INJECTION_PATTERNS[] = { + "('|\").*?('|\")", // Quote sequences + "\\bor\\b.*=.*\\bor\\b", // OR 1=1 + "\\band\\b.*=.*\\band\\b", // AND 1=1 + "union.*select", // UNION SELECT + "drop.*table", // DROP TABLE + "exec.*xp_", // SQL Server exec + ";.*--", // Comment injection + "/\\*.*\\*/", // Block comments + "concat\\(", // CONCAT based attacks + "char\\(", // CHAR based attacks + "0x[0-9a-f]+", // Hex encoded + NULL +}; + +// Suspicious Keywords +static const char* SUSPICIOUS_KEYWORDS[] = { + "sleep(", "waitfor delay", "benchmark(", "pg_sleep", + "load_file", "into outfile", "dumpfile", + "script>", "javascript:", "onerror=", "onload=", + NULL +}; + +// Thresholds +#define DEFAULT_RATE_LIMIT 100 // queries per minute +#define DEFAULT_RISK_THRESHOLD 70 // 0-100 +#define DEFAULT_SIMILARITY_THRESHOLD 85 // 0-100 +#define USER_STATS_WINDOW 3600 // 1 hour in seconds +#define MAX_RECENT_QUERIES 100 + +// ============================================================================ +// Constructor/Destructor +// ============================================================================ + +Anomaly_Detector::Anomaly_Detector() : vector_db(NULL) { + config.enabled = true; + config.risk_threshold = DEFAULT_RISK_THRESHOLD; + config.similarity_threshold = DEFAULT_SIMILARITY_THRESHOLD; + config.rate_limit = DEFAULT_RATE_LIMIT; + config.auto_block = true; + config.log_only = false; +} + +Anomaly_Detector::~Anomaly_Detector() { + close(); +} + +// ============================================================================ +// Initialization +// ============================================================================ + +/** + * @brief Initialize the anomaly detector + * + * Sets up the vector database connection and loads any + * pre-configured threat patterns from storage. + */ +int Anomaly_Detector::init() { + proxy_info("Anomaly: Initializing Anomaly Detector v%s\n", ANOMALY_DETECTOR_VERSION); + + // Vector DB will be provided by AI_Features_Manager + // For now, we'll work without it for basic pattern detection + + proxy_info("Anomaly: Anomaly Detector initialized with %zu injection patterns\n", + sizeof(SQL_INJECTION_PATTERNS) / sizeof(SQL_INJECTION_PATTERNS[0]) - 1); + return 0; +} + +/** + * @brief Close and cleanup resources + */ +void Anomaly_Detector::close() { + // Clear user statistics + clear_user_statistics(); + + proxy_info("Anomaly: Anomaly Detector closed\n"); +} + +// ============================================================================ +// Query Normalization +// ============================================================================ + +/** + * @brief Normalize SQL query for pattern matching + * + * Normalization steps: + * 1. Convert to lowercase + * 2. Remove extra whitespace + * 3. Replace string literals with placeholders + * 4. Replace numeric literals with placeholders + * 5. Remove comments + * + * @param query Original SQL query + * @return Normalized query pattern + */ +std::string Anomaly_Detector::normalize_query(const std::string& query) { + std::string normalized = query; + + // Convert to lowercase + std::transform(normalized.begin(), normalized.end(), normalized.begin(), ::tolower); + + // Remove SQL comments + std::regex comment_regex("--.*?$|/\\*.*?\\*/", std::regex::multiline); + normalized = std::regex_replace(normalized, comment_regex, ""); + + // Replace string literals with placeholder + std::regex string_regex("'[^']*'|\"[^\"]*\""); + normalized = std::regex_replace(normalized, string_regex, "?"); + + // Replace numeric literals with placeholder + std::regex numeric_regex("\\b\\d+\\b"); + normalized = std::regex_replace(normalized, numeric_regex, "N"); + + // Normalize whitespace + std::regex whitespace_regex("\\s+"); + normalized = std::regex_replace(normalized, whitespace_regex, " "); + + // Trim leading/trailing whitespace + normalized.erase(0, normalized.find_first_not_of(" \t\n\r")); + normalized.erase(normalized.find_last_not_of(" \t\n\r") + 1); + + return normalized; +} + +// ============================================================================ +// SQL Injection Detection +// ============================================================================ + +/** + * @brief Check for SQL injection patterns + * + * Uses regex-based pattern matching to detect common SQL injection + * attack vectors including: + * - Tautologies (OR 1=1) + * - Union-based injection + * - Comment-based injection + * - Stacked queries + * - String/character encoding attacks + * + * @param query SQL query to check + * @return AnomalyResult with injection details + */ +AnomalyResult Anomaly_Detector::check_sql_injection(const std::string& query) { + AnomalyResult result; + result.is_anomaly = false; + result.risk_score = 0.0f; + result.anomaly_type = "sql_injection"; + result.should_block = false; + + try { + std::string query_lower = query; + std::transform(query_lower.begin(), query_lower.end(), query_lower.begin(), ::tolower); + + // Check each injection pattern + int pattern_matches = 0; + for (int i = 0; SQL_INJECTION_PATTERNS[i] != NULL; i++) { + std::regex pattern(SQL_INJECTION_PATTERNS[i], std::regex::icase); + if (std::regex_search(query, pattern)) { + pattern_matches++; + result.matched_rules.push_back(std::string("injection_pattern_") + std::to_string(i)); + } + } + + // Check suspicious keywords + for (int i = 0; SUSPICIOUS_KEYWORDS[i] != NULL; i++) { + if (query_lower.find(SUSPICIOUS_KEYWORDS[i]) != std::string::npos) { + pattern_matches++; + result.matched_rules.push_back(std::string("suspicious_keyword_") + std::to_string(i)); + } + } + + // Calculate risk score based on pattern matches + if (pattern_matches > 0) { + result.is_anomaly = true; + result.risk_score = std::min(1.0f, pattern_matches * 0.3f); + + std::ostringstream explanation; + explanation << "SQL injection patterns detected: " << pattern_matches << " matches"; + result.explanation = explanation.str(); + + // Auto-block if high risk and auto-block enabled + if (result.risk_score >= config.risk_threshold / 100.0f && config.auto_block) { + result.should_block = true; + } + + proxy_debug(PROXY_DEBUG_ANOMALY, 3, + "Anomaly: SQL injection detected in query: %s (risk: %.2f)\n", + query.c_str(), result.risk_score); + } + + } catch (const std::regex_error& e) { + proxy_error("Anomaly: Regex error in injection check: %s\n", e.what()); + } catch (const std::exception& e) { + proxy_error("Anomaly: Error in injection check: %s\n", e.what()); + } + + return result; +} + +// ============================================================================ +// Rate Limiting +// ============================================================================ + +/** + * @brief Check rate limiting per user/host + * + * Tracks the number of queries per user/host within a time window + * to detect potential DoS attacks or brute force attempts. + * + * @param user Username + * @param client_host Client IP address + * @return AnomalyResult with rate limit details + */ +AnomalyResult Anomaly_Detector::check_rate_limiting(const std::string& user, + const std::string& client_host) { + AnomalyResult result; + result.is_anomaly = false; + result.risk_score = 0.0f; + result.anomaly_type = "rate_limit"; + result.should_block = false; + + if (!config.enabled) { + return result; + } + + // Get current time + uint64_t current_time = (uint64_t)time(NULL); + std::string key = user + "@" + client_host; + + // Get or create user stats + UserStats& stats = user_statistics[key]; + + // Check if we're within the time window + if (current_time - stats.last_query_time > USER_STATS_WINDOW) { + // Window expired, reset counter + stats.query_count = 0; + stats.recent_queries.clear(); + } + + // Increment query count + stats.query_count++; + stats.last_query_time = current_time; + + // Check if rate limit exceeded + if (stats.query_count > (uint64_t)config.rate_limit) { + result.is_anomaly = true; + // Risk score increases with excess queries + float excess_ratio = (float)(stats.query_count - config.rate_limit) / config.rate_limit; + result.risk_score = std::min(1.0f, 0.5f + excess_ratio); + + std::ostringstream explanation; + explanation << "Rate limit exceeded: " << stats.query_count + << " queries per " << USER_STATS_WINDOW << " seconds (limit: " + << config.rate_limit << ")"; + result.explanation = explanation.str(); + result.matched_rules.push_back("rate_limit_exceeded"); + + if (config.auto_block) { + result.should_block = true; + } + + proxy_warning("Anomaly: Rate limit exceeded for %s: %lu queries\n", + key.c_str(), stats.query_count); + } + + return result; +} + +// ============================================================================ +// Statistical Anomaly Detection +// ============================================================================ + +/** + * @brief Detect statistical anomalies in query behavior + * + * Analyzes query patterns to detect unusual behavior such as: + * - Abnormally large result sets + * - Unexpected execution times + * - Queries affecting many rows + * - Unusual query patterns for the user + * + * @param fp Query fingerprint + * @return AnomalyResult with statistical anomaly details + */ +AnomalyResult Anomaly_Detector::check_statistical_anomaly(const QueryFingerprint& fp) { + AnomalyResult result; + result.is_anomaly = false; + result.risk_score = 0.0f; + result.anomaly_type = "statistical"; + result.should_block = false; + + if (!config.enabled) { + return result; + } + + std::string key = fp.user + "@" + fp.client_host; + UserStats& stats = user_statistics[key]; + + // Calculate some basic statistics + uint64_t avg_queries = 10; // Default baseline + float z_score = 0.0f; + + if (stats.query_count > avg_queries * 3) { + // Query count is more than 3 standard deviations above mean + result.is_anomaly = true; + z_score = (float)(stats.query_count - avg_queries) / avg_queries; + result.risk_score = std::min(1.0f, z_score / 5.0f); // Normalize + + std::ostringstream explanation; + explanation << "Unusually high query rate: " << stats.query_count + << " queries (baseline: " << avg_queries << ")"; + result.explanation = explanation.str(); + result.matched_rules.push_back("high_query_rate"); + + proxy_debug(PROXY_DEBUG_ANOMALY, 3, + "Anomaly: Statistical anomaly for %s: z-score=%.2f\n", + key.c_str(), z_score); + } + + // Check for abnormal execution time or rows affected + if (fp.execution_time_ms > 5000) { // 5 seconds + result.is_anomaly = true; + result.risk_score = std::max(result.risk_score, 0.3f); + + if (!result.explanation.empty()) { + result.explanation += "; "; + } + result.explanation += "Long execution time detected"; + result.matched_rules.push_back("long_execution_time"); + } + + if (fp.affected_rows > 10000) { + result.is_anomaly = true; + result.risk_score = std::max(result.risk_score, 0.2f); + + if (!result.explanation.empty()) { + result.explanation += "; "; + } + result.explanation += "Large result set detected"; + result.matched_rules.push_back("large_result_set"); + } + + return result; +} + +// ============================================================================ +// Embedding-based Similarity Detection +// ============================================================================ + +/** + * @brief Check embedding-based similarity to known threats + * + * Compares the query embedding to embeddings of known malicious queries + * stored in the vector database. This can detect novel attacks that + * don't match explicit patterns. + * + * @param query SQL query + * @param embedding Query vector embedding (if available) + * @return AnomalyResult with similarity details + */ +AnomalyResult Anomaly_Detector::check_embedding_similarity(const std::string& query, + const std::vector& embedding) { + AnomalyResult result; + result.is_anomaly = false; + result.risk_score = 0.0f; + result.anomaly_type = "embedding_similarity"; + result.should_block = false; + + if (!config.enabled || !vector_db) { + // Can't do embedding check without vector DB + return result; + } + + // If embedding not provided, generate it + std::vector query_embedding = embedding; + if (query_embedding.empty()) { + query_embedding = get_query_embedding(query); + } + + if (query_embedding.empty()) { + return result; + } + + // Convert embedding to JSON for sqlite-vec MATCH + std::string embedding_json = "["; + for (size_t i = 0; i < query_embedding.size(); i++) { + if (i > 0) embedding_json += ","; + embedding_json += std::to_string(query_embedding[i]); + } + embedding_json += "]"; + + // Calculate distance threshold from similarity + // Similarity 0-100 -> Distance 0-2 (cosine distance: 0=similar, 2=dissimilar) + float distance_threshold = 2.0f - (config.similarity_threshold / 50.0f); + + // Search for similar threat patterns + char search[1024]; + snprintf(search, sizeof(search), + "SELECT p.pattern_name, p.pattern_type, p.severity, " + " vec_distance_cosine(v.embedding, '%s') as distance " + "FROM anomaly_patterns p " + "JOIN anomaly_patterns_vec v ON p.id = v.rowid " + "WHERE v.embedding MATCH '%s' " + "AND distance < %f " + "ORDER BY distance " + "LIMIT 5", + embedding_json.c_str(), embedding_json.c_str(), distance_threshold); + + // Execute search + sqlite3* db = vector_db->get_db(); + sqlite3_stmt* stmt = NULL; + int rc = (*proxy_sqlite3_prepare_v2)(db, search, -1, &stmt, NULL); + + if (rc != SQLITE_OK) { + proxy_debug(PROXY_DEBUG_ANOMALY, 3, "Embedding search prepare failed: %s", (*proxy_sqlite3_errmsg)(db)); + return result; + } + + // Check if any threat patterns matched + rc = (*proxy_sqlite3_step)(stmt); + if (rc == SQLITE_ROW) { + // Found similar threat pattern + result.is_anomaly = true; + + // Extract pattern info + const char* pattern_name = reinterpret_cast((*proxy_sqlite3_column_text)(stmt, 0)); + const char* pattern_type = reinterpret_cast((*proxy_sqlite3_column_text)(stmt, 1)); + int severity = (*proxy_sqlite3_column_int)(stmt, 2); + double distance = (*proxy_sqlite3_column_double)(stmt, 3); + + // Calculate risk score based on severity and similarity + // - Base score from severity (1-10) -> 0.1-1.0 + // - Boost by similarity (lower distance = higher risk) + result.risk_score = (severity / 10.0f) * (1.0f - (distance / 2.0f)); + + // Set anomaly type + result.anomaly_type = "embedding_similarity"; + + // Build explanation + char explanation[512]; + snprintf(explanation, sizeof(explanation), + "Query similar to known threat pattern '%s' (type: %s, severity: %d, distance: %.2f)", + pattern_name ? pattern_name : "unknown", + pattern_type ? pattern_type : "unknown", + severity, distance); + result.explanation = explanation; + + // Add matched pattern to rules + if (pattern_name) { + result.matched_rules.push_back(std::string("pattern:") + pattern_name); + } + + // Determine if should block + result.should_block = (result.risk_score > (config.risk_threshold / 100.0f)); + + proxy_info("Anomaly: Embedding similarity detected (pattern: %s, score: %.2f)\n", + pattern_name ? pattern_name : "unknown", result.risk_score); + } + + sqlite3_finalize(stmt); + + proxy_debug(PROXY_DEBUG_ANOMALY, 3, + "Anomaly: Embedding similarity check performed\n"); + + return result; +} + +/** + * @brief Get vector embedding for a query + * + * Generates a vector representation of the query using a sentence + * transformer or similar embedding model. + * + * Uses the GenAI module (GloGATH) for embedding generation via llama-server. + * + * @param query SQL query + * @return Vector embedding (empty if not available) + */ +std::vector Anomaly_Detector::get_query_embedding(const std::string& query) { + if (!GloGATH) { + proxy_debug(PROXY_DEBUG_ANOMALY, 3, "GenAI handler not available for embedding"); + return {}; + } + + // Normalize query first for better embedding quality + std::string normalized = normalize_query(query); + + // Generate embedding using GenAI + GenAI_EmbeddingResult result = GloGATH->embed_documents({normalized}); + + if (!result.data || result.count == 0) { + proxy_debug(PROXY_DEBUG_ANOMALY, 3, "Failed to generate embedding"); + return {}; + } + + // Convert to std::vector + std::vector embedding(result.data, result.data + result.embedding_size); + + // Free the result data (GenAI allocates with malloc) + if (result.data) { + free(result.data); + } + + proxy_debug(PROXY_DEBUG_ANOMALY, 3, "Generated embedding with %zu dimensions", embedding.size()); + return embedding; +} + +// ============================================================================ +// User Statistics Management +// ============================================================================ + +/** + * @brief Update user statistics with query fingerprint + * + * Tracks user behavior for statistical anomaly detection. + * + * @param fp Query fingerprint + */ +void Anomaly_Detector::update_user_statistics(const QueryFingerprint& fp) { + if (!config.enabled) { + return; + } + + std::string key = fp.user + "@" + fp.client_host; + UserStats& stats = user_statistics[key]; + + // Add to recent queries + stats.recent_queries.push_back(fp.query_pattern); + + // Keep only recent queries + if (stats.recent_queries.size() > MAX_RECENT_QUERIES) { + stats.recent_queries.erase(stats.recent_queries.begin()); + } + + stats.last_query_time = fp.timestamp; + stats.query_count++; + + // Cleanup old entries periodically + static int cleanup_counter = 0; + if (++cleanup_counter % 1000 == 0) { + uint64_t current_time = (uint64_t)time(NULL); + auto it = user_statistics.begin(); + while (it != user_statistics.end()) { + if (current_time - it->second.last_query_time > USER_STATS_WINDOW * 2) { + it = user_statistics.erase(it); + } else { + ++it; + } + } + } +} + +// ============================================================================ +// Main Analysis Method +// ============================================================================ + +/** + * @brief Main entry point for anomaly detection + * + * Runs the multi-stage detection pipeline: + * 1. SQL Injection Pattern Detection + * 2. Rate Limiting Check + * 3. Statistical Anomaly Detection + * 4. Embedding Similarity Check (if vector DB available) + * + * @param query SQL query to analyze + * @param user Username + * @param client_host Client IP address + * @param schema Database schema name + * @return AnomalyResult with combined analysis + */ +AnomalyResult Anomaly_Detector::analyze(const std::string& query, const std::string& user, + const std::string& client_host, const std::string& schema) { + AnomalyResult combined_result; + combined_result.is_anomaly = false; + combined_result.risk_score = 0.0f; + combined_result.should_block = false; + + if (!config.enabled) { + return combined_result; + } + + proxy_debug(PROXY_DEBUG_ANOMALY, 3, + "Anomaly: Analyzing query from %s@%s\n", + user.c_str(), client_host.c_str()); + + // Run all detection stages + AnomalyResult injection_result = check_sql_injection(query); + AnomalyResult rate_result = check_rate_limiting(user, client_host); + + // Build fingerprint for statistical analysis + QueryFingerprint fp; + fp.query_pattern = normalize_query(query); + fp.user = user; + fp.client_host = client_host; + fp.schema = schema; + fp.timestamp = (uint64_t)time(NULL); + + AnomalyResult stat_result = check_statistical_anomaly(fp); + + // Embedding similarity (optional) + std::vector embedding; + AnomalyResult embed_result = check_embedding_similarity(query, embedding); + + // Combine results + combined_result.is_anomaly = injection_result.is_anomaly || + rate_result.is_anomaly || + stat_result.is_anomaly || + embed_result.is_anomaly; + + // Take maximum risk score + combined_result.risk_score = std::max({injection_result.risk_score, + rate_result.risk_score, + stat_result.risk_score, + embed_result.risk_score}); + + // Combine explanations + std::vector explanations; + if (!injection_result.explanation.empty()) { + explanations.push_back(injection_result.explanation); + } + if (!rate_result.explanation.empty()) { + explanations.push_back(rate_result.explanation); + } + if (!stat_result.explanation.empty()) { + explanations.push_back(stat_result.explanation); + } + if (!embed_result.explanation.empty()) { + explanations.push_back(embed_result.explanation); + } + + if (!explanations.empty()) { + combined_result.explanation = explanations[0]; + for (size_t i = 1; i < explanations.size(); i++) { + combined_result.explanation += "; " + explanations[i]; + } + } + + // Combine matched rules + combined_result.matched_rules = injection_result.matched_rules; + combined_result.matched_rules.insert(combined_result.matched_rules.end(), + rate_result.matched_rules.begin(), + rate_result.matched_rules.end()); + combined_result.matched_rules.insert(combined_result.matched_rules.end(), + stat_result.matched_rules.begin(), + stat_result.matched_rules.end()); + combined_result.matched_rules.insert(combined_result.matched_rules.end(), + embed_result.matched_rules.begin(), + embed_result.matched_rules.end()); + + // Determine if should block + combined_result.should_block = injection_result.should_block || + rate_result.should_block || + (combined_result.risk_score >= config.risk_threshold / 100.0f && config.auto_block); + + // Update user statistics + update_user_statistics(fp); + + // Log anomaly if detected + if (combined_result.is_anomaly) { + if (config.log_only) { + proxy_warning("Anomaly: Detected (log-only mode): %s (risk: %.2f)\n", + combined_result.explanation.c_str(), combined_result.risk_score); + } else if (combined_result.should_block) { + proxy_error("Anomaly: BLOCKED: %s (risk: %.2f)\n", + combined_result.explanation.c_str(), combined_result.risk_score); + } else { + proxy_warning("Anomaly: Detected: %s (risk: %.2f)\n", + combined_result.explanation.c_str(), combined_result.risk_score); + } + } + + return combined_result; +} + +// ============================================================================ +// Threat Pattern Management +// ============================================================================ + +/** + * @brief Add a threat pattern to the database + * + * @param pattern_name Human-readable name + * @param query_example Example query + * @param pattern_type Type of threat (injection, flooding, etc.) + * @param severity Severity level (0-100) + * @return Pattern ID or -1 on error + */ +int Anomaly_Detector::add_threat_pattern(const std::string& pattern_name, + const std::string& query_example, + const std::string& pattern_type, + int severity) { + proxy_info("Anomaly: Adding threat pattern: %s (type: %s, severity: %d)\n", + pattern_name.c_str(), pattern_type.c_str(), severity); + + if (!vector_db) { + proxy_error("Anomaly: Cannot add pattern - no vector DB\n"); + return -1; + } + + // Generate embedding for the query example + std::vector embedding = get_query_embedding(query_example); + if (embedding.empty()) { + proxy_error("Anomaly: Failed to generate embedding for threat pattern\n"); + return -1; + } + + // Insert into main table with embedding BLOB + sqlite3* db = vector_db->get_db(); + sqlite3_stmt* stmt = NULL; + const char* insert = "INSERT INTO anomaly_patterns " + "(pattern_name, pattern_type, query_example, embedding, severity) " + "VALUES (?, ?, ?, ?, ?)"; + + int rc = (*proxy_sqlite3_prepare_v2)(db, insert, -1, &stmt, NULL); + if (rc != SQLITE_OK) { + proxy_error("Anomaly: Failed to prepare pattern insert: %s\n", (*proxy_sqlite3_errmsg)(db)); + return -1; + } + + // Bind values + (*proxy_sqlite3_bind_text)(stmt, 1, pattern_name.c_str(), -1, SQLITE_TRANSIENT); + (*proxy_sqlite3_bind_text)(stmt, 2, pattern_type.c_str(), -1, SQLITE_TRANSIENT); + (*proxy_sqlite3_bind_text)(stmt, 3, query_example.c_str(), -1, SQLITE_TRANSIENT); + (*proxy_sqlite3_bind_blob)(stmt, 4, embedding.data(), embedding.size() * sizeof(float), SQLITE_TRANSIENT); + (*proxy_sqlite3_bind_int)(stmt, 5, severity); + + // Execute insert + rc = (*proxy_sqlite3_step)(stmt); + if (rc != SQLITE_DONE) { + proxy_error("Anomaly: Failed to insert pattern: %s\n", sqlite3_errmsg(db)); + sqlite3_finalize(stmt); + return -1; + } + + sqlite3_finalize(stmt); + + // Get the inserted rowid + sqlite3_int64 rowid = (*proxy_sqlite3_last_insert_rowid)(db); + + // Update virtual table (sqlite-vec needs explicit rowid insertion) + char update_vec[256]; + snprintf(update_vec, sizeof(update_vec), + "INSERT INTO anomaly_patterns_vec(rowid) VALUES (%lld)", rowid); + + char* err = NULL; + rc = sqlite3_exec(db, update_vec, NULL, NULL, &err); + if (rc != SQLITE_OK) { + proxy_error("Anomaly: Failed to update vec table: %s\n", err ? err : "unknown"); + if (err) sqlite3_free(err); + return -1; + } + + proxy_info("Anomaly: Added threat pattern '%s' (id: %lld)\n", pattern_name.c_str(), rowid); + return (int)rowid; +} + +/** + * @brief List all threat patterns + * + * @return JSON array of threat patterns + */ +std::string Anomaly_Detector::list_threat_patterns() { + if (!vector_db) { + return "[]"; + } + + json patterns = json::array(); + + sqlite3* db = vector_db->get_db(); + const char* query = "SELECT id, pattern_name, pattern_type, query_example, severity, created_at " + "FROM anomaly_patterns ORDER BY severity DESC"; + + sqlite3_stmt* stmt = NULL; + int rc = sqlite3_prepare_v2(db, query, -1, &stmt, NULL); + + if (rc != SQLITE_OK) { + proxy_error("Anomaly: Failed to query threat patterns: %s\n", sqlite3_errmsg(db)); + return "[]"; + } + + while ((*proxy_sqlite3_step)(stmt) == SQLITE_ROW) { + json pattern; + pattern["id"] = (*proxy_sqlite3_column_int64)(stmt, 0); + const char* name = reinterpret_cast((*proxy_sqlite3_column_text)(stmt, 1)); + const char* type = reinterpret_cast((*proxy_sqlite3_column_text)(stmt, 2)); + const char* example = reinterpret_cast((*proxy_sqlite3_column_text)(stmt, 3)); + pattern["pattern_name"] = name ? name : ""; + pattern["pattern_type"] = type ? type : ""; + pattern["query_example"] = example ? example : ""; + pattern["severity"] = (*proxy_sqlite3_column_int)(stmt, 4); + pattern["created_at"] = (*proxy_sqlite3_column_int64)(stmt, 5); + patterns.push_back(pattern); + } + + sqlite3_finalize(stmt); + + return patterns.dump(); +} + +/** + * @brief Remove a threat pattern + * + * @param pattern_id Pattern ID to remove + * @return true if removed, false otherwise + */ +bool Anomaly_Detector::remove_threat_pattern(int pattern_id) { + proxy_info("Anomaly: Removing threat pattern: %d\n", pattern_id); + + if (!vector_db) { + proxy_error("Anomaly: Cannot remove pattern - no vector DB\n"); + return false; + } + + sqlite3* db = vector_db->get_db(); + + // First, remove from virtual table + char del_vec[256]; + snprintf(del_vec, sizeof(del_vec), "DELETE FROM anomaly_patterns_vec WHERE rowid = %d", pattern_id); + char* err = NULL; + int rc = sqlite3_exec(db, del_vec, NULL, NULL, &err); + if (rc != SQLITE_OK) { + proxy_error("Anomaly: Failed to delete from vec table: %s\n", err ? err : "unknown"); + if (err) sqlite3_free(err); + return false; + } + + // Then, remove from main table + snprintf(del_vec, sizeof(del_vec), "DELETE FROM anomaly_patterns WHERE id = %d", pattern_id); + rc = sqlite3_exec(db, del_vec, NULL, NULL, &err); + if (rc != SQLITE_OK) { + proxy_error("Anomaly: Failed to delete pattern: %s\n", err ? err : "unknown"); + if (err) sqlite3_free(err); + return false; + } + + proxy_info("Anomaly: Removed threat pattern %d\n", pattern_id); + return true; +} + +// ============================================================================ +// Statistics and Monitoring +// ============================================================================ + +/** + * @brief Get anomaly detection statistics + * + * @return JSON string with statistics + */ +std::string Anomaly_Detector::get_statistics() { + json stats; + + stats["users_tracked"] = user_statistics.size(); + stats["config"] = { + {"enabled", config.enabled}, + {"risk_threshold", config.risk_threshold}, + {"similarity_threshold", config.similarity_threshold}, + {"rate_limit", config.rate_limit}, + {"auto_block", config.auto_block}, + {"log_only", config.log_only} + }; + + // Count total queries + uint64_t total_queries = 0; + for (const auto& entry : user_statistics) { + total_queries += entry.second.query_count; + } + stats["total_queries_tracked"] = total_queries; + + // Count threat patterns + if (vector_db) { + sqlite3* db = vector_db->get_db(); + const char* count_query = "SELECT COUNT(*) FROM anomaly_patterns"; + sqlite3_stmt* stmt = NULL; + int rc = sqlite3_prepare_v2(db, count_query, -1, &stmt, NULL); + + if (rc == SQLITE_OK) { + rc = (*proxy_sqlite3_step)(stmt); + if (rc == SQLITE_ROW) { + stats["threat_patterns_count"] = sqlite3_column_int(stmt, 0); + } + sqlite3_finalize(stmt); + } + + // Count by pattern type + const char* type_query = "SELECT pattern_type, COUNT(*) FROM anomaly_patterns GROUP BY pattern_type"; + rc = sqlite3_prepare_v2(db, type_query, -1, &stmt, NULL); + + if (rc == SQLITE_OK) { + json by_type = json::object(); + while ((*proxy_sqlite3_step)(stmt) == SQLITE_ROW) { + const char* type = reinterpret_cast(sqlite3_column_text(stmt, 0)); + int count = sqlite3_column_int(stmt, 1); + if (type) { + by_type[type] = count; + } + } + sqlite3_finalize(stmt); + stats["threat_patterns_by_type"] = by_type; + } + } + + return stats.dump(); +} + +/** + * @brief Clear all user statistics + */ +void Anomaly_Detector::clear_user_statistics() { + size_t count = user_statistics.size(); + user_statistics.clear(); + proxy_info("Anomaly: Cleared statistics for %zu users\n", count); +} diff --git a/lib/Discovery_Schema.cpp b/lib/Discovery_Schema.cpp index 140458d4c..e2b1f7599 100644 --- a/lib/Discovery_Schema.cpp +++ b/lib/Discovery_Schema.cpp @@ -553,7 +553,7 @@ int Discovery_Schema::create_run( (*proxy_sqlite3_bind_text)(stmt, 3, notes.c_str(), -1, SQLITE_TRANSIENT); SAFE_SQLITE3_STEP2(stmt); - int run_id = (int)sqlite3_last_insert_rowid(db->get_db()); + int run_id = (int)(*proxy_sqlite3_last_insert_rowid)(db->get_db()); (*proxy_sqlite3_finalize)(stmt); return run_id; @@ -618,7 +618,7 @@ int Discovery_Schema::create_agent_run( int rc = db->prepare_v2(sql, &stmt); if (rc != SQLITE_OK) { - proxy_error("Failed to prepare agent_runs insert: %s\n", sqlite3_errstr(rc)); + proxy_error("Failed to prepare agent_runs insert: %s\n", (*proxy_sqlite3_errstr)(rc)); return -1; } @@ -639,11 +639,11 @@ int Discovery_Schema::create_agent_run( (*proxy_sqlite3_finalize)(stmt); if (step_rc != SQLITE_DONE) { - proxy_error("Failed to insert into agent_runs (run_id=%d): %s\n", run_id, sqlite3_errstr(step_rc)); + proxy_error("Failed to insert into agent_runs (run_id=%d): %s\n", run_id, (*proxy_sqlite3_errstr)(step_rc)); return -1; } - int agent_run_id = (int)sqlite3_last_insert_rowid(db->get_db()); + int agent_run_id = (int)(*proxy_sqlite3_last_insert_rowid)(db->get_db()); proxy_info("Created agent_run_id=%d for run_id=%d\n", agent_run_id, run_id); return agent_run_id; } @@ -746,7 +746,7 @@ int Discovery_Schema::insert_schema( (*proxy_sqlite3_bind_text)(stmt, 4, collation.c_str(), -1, SQLITE_TRANSIENT); SAFE_SQLITE3_STEP2(stmt); - int schema_id = (int)sqlite3_last_insert_rowid(db->get_db()); + int schema_id = (int)(*proxy_sqlite3_last_insert_rowid)(db->get_db()); (*proxy_sqlite3_finalize)(stmt); return schema_id; @@ -794,7 +794,7 @@ int Discovery_Schema::insert_object( (*proxy_sqlite3_bind_text)(stmt, 12, definition_sql.c_str(), -1, SQLITE_TRANSIENT); SAFE_SQLITE3_STEP2(stmt); - int object_id = (int)sqlite3_last_insert_rowid(db->get_db()); + int object_id = (int)(*proxy_sqlite3_last_insert_rowid)(db->get_db()); (*proxy_sqlite3_finalize)(stmt); return object_id; @@ -847,7 +847,7 @@ int Discovery_Schema::insert_column( (*proxy_sqlite3_bind_int)(stmt, 16, is_id_like); SAFE_SQLITE3_STEP2(stmt); - int column_id = (int)sqlite3_last_insert_rowid(db->get_db()); + int column_id = (int)(*proxy_sqlite3_last_insert_rowid)(db->get_db()); (*proxy_sqlite3_finalize)(stmt); return column_id; @@ -877,7 +877,7 @@ int Discovery_Schema::insert_index( (*proxy_sqlite3_bind_int64)(stmt, 6, (sqlite3_int64)cardinality); SAFE_SQLITE3_STEP2(stmt); - int index_id = (int)sqlite3_last_insert_rowid(db->get_db()); + int index_id = (int)(*proxy_sqlite3_last_insert_rowid)(db->get_db()); (*proxy_sqlite3_finalize)(stmt); return index_id; @@ -936,7 +936,7 @@ int Discovery_Schema::insert_foreign_key( (*proxy_sqlite3_bind_text)(stmt, 7, on_delete.c_str(), -1, SQLITE_TRANSIENT); SAFE_SQLITE3_STEP2(stmt); - int fk_id = (int)sqlite3_last_insert_rowid(db->get_db()); + int fk_id = (int)(*proxy_sqlite3_last_insert_rowid)(db->get_db()); (*proxy_sqlite3_finalize)(stmt); return fk_id; @@ -1565,7 +1565,7 @@ int Discovery_Schema::append_agent_event( (*proxy_sqlite3_bind_text)(stmt, 3, payload_json.c_str(), -1, SQLITE_TRANSIENT); SAFE_SQLITE3_STEP2(stmt); - int event_id = (int)sqlite3_last_insert_rowid(db->get_db()); + int event_id = (int)(*proxy_sqlite3_last_insert_rowid)(db->get_db()); (*proxy_sqlite3_finalize)(stmt); return event_id; @@ -1726,7 +1726,7 @@ int Discovery_Schema::upsert_llm_domain( (*proxy_sqlite3_bind_double)(stmt, 6, confidence); SAFE_SQLITE3_STEP2(stmt); - int domain_id = (int)sqlite3_last_insert_rowid(db->get_db()); + int domain_id = (int)(*proxy_sqlite3_last_insert_rowid)(db->get_db()); (*proxy_sqlite3_finalize)(stmt); // Insert into FTS index (use INSERT OR REPLACE for upsert semantics) @@ -1842,7 +1842,7 @@ int Discovery_Schema::upsert_llm_metric( (*proxy_sqlite3_bind_double)(stmt, 11, confidence); SAFE_SQLITE3_STEP2(stmt); - int metric_id = (int)sqlite3_last_insert_rowid(db->get_db()); + int metric_id = (int)(*proxy_sqlite3_last_insert_rowid)(db->get_db()); (*proxy_sqlite3_finalize)(stmt); // Insert into FTS index (use INSERT OR REPLACE for upsert semantics) @@ -1892,7 +1892,7 @@ int Discovery_Schema::add_question_template( (*proxy_sqlite3_bind_double)(stmt, 8, confidence); SAFE_SQLITE3_STEP2(stmt); - int template_id = (int)sqlite3_last_insert_rowid(db->get_db()); + int template_id = (int)(*proxy_sqlite3_last_insert_rowid)(db->get_db()); (*proxy_sqlite3_finalize)(stmt); // Insert into FTS index @@ -1944,7 +1944,7 @@ int Discovery_Schema::add_llm_note( (*proxy_sqlite3_bind_text)(stmt, 8, tags_json.c_str(), -1, SQLITE_TRANSIENT); SAFE_SQLITE3_STEP2(stmt); - int note_id = (int)sqlite3_last_insert_rowid(db->get_db()); + int note_id = (int)(*proxy_sqlite3_last_insert_rowid)(db->get_db()); (*proxy_sqlite3_finalize)(stmt); // Insert into FTS index @@ -2180,11 +2180,11 @@ int Discovery_Schema::log_llm_search( return -1; } - sqlite3_bind_int(stmt, 1, run_id); - sqlite3_bind_text(stmt, 2, query.c_str(), -1, SQLITE_TRANSIENT); - sqlite3_bind_int(stmt, 3, lmt); + (*proxy_sqlite3_bind_int)(stmt, 1, run_id); + (*proxy_sqlite3_bind_text)(stmt, 2, query.c_str(), -1, SQLITE_TRANSIENT); + (*proxy_sqlite3_bind_int)(stmt, 3, lmt); - rc = sqlite3_step(stmt); + rc = (*proxy_sqlite3_step)(stmt); (*proxy_sqlite3_finalize)(stmt); if (rc != SQLITE_DONE) { @@ -2212,26 +2212,26 @@ int Discovery_Schema::log_query_tool_call( return -1; } - sqlite3_bind_text(stmt, 1, tool_name.c_str(), -1, SQLITE_TRANSIENT); + (*proxy_sqlite3_bind_text)(stmt, 1, tool_name.c_str(), -1, SQLITE_TRANSIENT); if (!schema.empty()) { - sqlite3_bind_text(stmt, 2, schema.c_str(), -1, SQLITE_TRANSIENT); + (*proxy_sqlite3_bind_text)(stmt, 2, schema.c_str(), -1, SQLITE_TRANSIENT); } else { - sqlite3_bind_null(stmt, 2); + (*proxy_sqlite3_bind_null)(stmt, 2); } if (run_id > 0) { - sqlite3_bind_int(stmt, 3, run_id); + (*proxy_sqlite3_bind_int)(stmt, 3, run_id); } else { - sqlite3_bind_null(stmt, 3); + (*proxy_sqlite3_bind_null)(stmt, 3); } - sqlite3_bind_int64(stmt, 4, start_time); - sqlite3_bind_int64(stmt, 5, execution_time); + (*proxy_sqlite3_bind_int64)(stmt, 4, start_time); + (*proxy_sqlite3_bind_int64)(stmt, 5, execution_time); if (!error.empty()) { - sqlite3_bind_text(stmt, 6, error.c_str(), -1, SQLITE_TRANSIENT); + (*proxy_sqlite3_bind_text)(stmt, 6, error.c_str(), -1, SQLITE_TRANSIENT); } else { - sqlite3_bind_null(stmt, 6); + (*proxy_sqlite3_bind_null)(stmt, 6); } - rc = sqlite3_step(stmt); + rc = (*proxy_sqlite3_step)(stmt); (*proxy_sqlite3_finalize)(stmt); if (rc != SQLITE_DONE) { diff --git a/lib/PgSQL_Monitor.cpp b/lib/PgSQL_Monitor.cpp index 8088abc51..7c7fd9c43 100644 --- a/lib/PgSQL_Monitor.cpp +++ b/lib/PgSQL_Monitor.cpp @@ -143,24 +143,24 @@ unique_ptr init_pgsql_thread_struct() { // Helper function for binding text void sqlite_bind_text(sqlite3_stmt* stmt, int index, const char* text) { int rc = (*proxy_sqlite3_bind_text)(stmt, index, text, -1, SQLITE_TRANSIENT); - ASSERT_SQLITE3_OK(rc, sqlite3_db_handle(stmt)); + ASSERT_SQLITE3_OK(rc, (*proxy_sqlite3_db_handle)(stmt)); } // Helper function for binding integers void sqlite_bind_int(sqlite3_stmt* stmt, int index, int value) { int rc = (*proxy_sqlite3_bind_int)(stmt, index, value); - ASSERT_SQLITE3_OK(rc, sqlite3_db_handle(stmt)); + ASSERT_SQLITE3_OK(rc, (*proxy_sqlite3_db_handle)(stmt)); } // Helper function for binding 64-bit integers void sqlite_bind_int64(sqlite3_stmt* stmt, int index, long long value) { int rc = (*proxy_sqlite3_bind_int64)(stmt, index, value); - ASSERT_SQLITE3_OK(rc, sqlite3_db_handle(stmt)); + ASSERT_SQLITE3_OK(rc, (*proxy_sqlite3_db_handle)(stmt)); } void sqlite_bind_null(sqlite3_stmt* stmt, int index) { int rc = (*proxy_sqlite3_bind_null)(stmt, index); - ASSERT_SQLITE3_OK(rc, sqlite3_db_handle(stmt)); + ASSERT_SQLITE3_OK(rc, (*proxy_sqlite3_db_handle)(stmt)); } // Helper function for executing a statement @@ -180,13 +180,13 @@ int sqlite_execute_statement(sqlite3_stmt* stmt) { // Helper function for clearing bindings void sqlite_clear_bindings(sqlite3_stmt* stmt) { int rc = (*proxy_sqlite3_clear_bindings)(stmt); - ASSERT_SQLITE3_OK(rc, sqlite3_db_handle(stmt)); + ASSERT_SQLITE3_OK(rc, (*proxy_sqlite3_db_handle)(stmt)); } // Helper function for resetting a statement void sqlite_reset_statement(sqlite3_stmt* stmt) { int rc = (*proxy_sqlite3_reset)(stmt); - ASSERT_SQLITE3_OK(rc, sqlite3_db_handle(stmt)); + ASSERT_SQLITE3_OK(rc, (*proxy_sqlite3_db_handle)(stmt)); } // Helper function for finalizing a statement diff --git a/lib/ProxySQL_Admin_Stats.cpp b/lib/ProxySQL_Admin_Stats.cpp index 3a1c433ca..4ff2ff6a3 100644 --- a/lib/ProxySQL_Admin_Stats.cpp +++ b/lib/ProxySQL_Admin_Stats.cpp @@ -437,7 +437,7 @@ void ProxySQL_Admin::p_update_stmt_metrics() { using row_bind_t = void (*)(int offset, SQLite3DB* db, sqlite3_stmt* stmt, SQLite3_row* row); -void sqlite3_bulk_step( +void (*proxy_sqlite3_bulk_step)( SQLite3DB* db, sqlite3_stmt* row_stmt, sqlite3_stmt* bulk_stmt, @@ -485,7 +485,7 @@ void stats_mysql_global___bind_row( template constexpr std::false_type always_false {}; template -const void sqlite3_global_stats_row_step( +const void (*proxy_sqlite3_global_stats_row_step)( SQLite3DB* db, sqlite3_stmt* stmt, const char* name, T val ) { char buf[32] = { 0 }; @@ -539,7 +539,7 @@ void ProxySQL_Admin::stats___mysql_global() { ASSERT_SQLITE_OK(rc, statsdb); sqlite3_stmt* const bulk_stmt { u_bulk_stmt.get() }; - sqlite3_bulk_step(statsdb, row_stmt, bulk_stmt, resultset, stats_mysql_global___bind_row); + (*proxy_sqlite3_bulk_step)(statsdb, row_stmt, bulk_stmt, resultset, stats_mysql_global___bind_row); delete resultset; resultset=NULL; @@ -547,7 +547,7 @@ void ProxySQL_Admin::stats___mysql_global() { resultset=MyHGM->SQL3_Get_ConnPool_Stats(); if (resultset) { - sqlite3_bulk_step(statsdb, row_stmt, bulk_stmt, resultset, stats_mysql_global___bind_row); + (*proxy_sqlite3_bulk_step)(statsdb, row_stmt, bulk_stmt, resultset, stats_mysql_global___bind_row); delete resultset; resultset=NULL; } @@ -555,12 +555,12 @@ void ProxySQL_Admin::stats___mysql_global() { { long long highwater, current = 0; (*proxy_sqlite3_status64)(SQLITE_STATUS_MEMORY_USED, ¤t, &highwater, 0); - sqlite3_global_stats_row_step(statsdb, row_stmt, "SQLite3_memory_bytes", current); + (*proxy_sqlite3_global_stats_row_step)(statsdb, row_stmt, "SQLite3_memory_bytes", current); } { unsigned long long connpool_mem=MyHGM->Get_Memory_Stats(); - sqlite3_global_stats_row_step(statsdb, row_stmt, "ConnPool_memory_bytes", connpool_mem); + (*proxy_sqlite3_global_stats_row_step)(statsdb, row_stmt, "ConnPool_memory_bytes", connpool_mem); } if (GloMyStmt) { @@ -580,32 +580,32 @@ void ProxySQL_Admin::stats___mysql_global() { &server_active_total ); - sqlite3_global_stats_row_step(statsdb, row_stmt, "Stmt_Client_Active_Total", client_active_total); - sqlite3_global_stats_row_step(statsdb, row_stmt, "Stmt_Client_Active_Unique", client_active_unique); - sqlite3_global_stats_row_step(statsdb, row_stmt, "Stmt_Server_Active_Total", server_active_total); - sqlite3_global_stats_row_step(statsdb, row_stmt, "Stmt_Server_Active_Unique", server_active_unique); - sqlite3_global_stats_row_step(statsdb, row_stmt, "Stmt_Max_Stmt_id", max_stmt_id); - sqlite3_global_stats_row_step(statsdb, row_stmt, "Stmt_Cached", cached); + (*proxy_sqlite3_global_stats_row_step)(statsdb, row_stmt, "Stmt_Client_Active_Total", client_active_total); + (*proxy_sqlite3_global_stats_row_step)(statsdb, row_stmt, "Stmt_Client_Active_Unique", client_active_unique); + (*proxy_sqlite3_global_stats_row_step)(statsdb, row_stmt, "Stmt_Server_Active_Total", server_active_total); + (*proxy_sqlite3_global_stats_row_step)(statsdb, row_stmt, "Stmt_Server_Active_Unique", server_active_unique); + (*proxy_sqlite3_global_stats_row_step)(statsdb, row_stmt, "Stmt_Max_Stmt_id", max_stmt_id); + (*proxy_sqlite3_global_stats_row_step)(statsdb, row_stmt, "Stmt_Cached", cached); } if (GloMyQC && (resultset= GloMyQC->SQL3_getStats())) { - sqlite3_bulk_step(statsdb, row_stmt, bulk_stmt, resultset, stats_mysql_global___bind_row); + (*proxy_sqlite3_bulk_step)(statsdb, row_stmt, bulk_stmt, resultset, stats_mysql_global___bind_row); delete resultset; resultset=NULL; } if (GloMyLdapAuth) { resultset=GloMyLdapAuth->SQL3_getStats(); - sqlite3_bulk_step(statsdb, row_stmt, bulk_stmt, resultset, stats_mysql_global___bind_row); + (*proxy_sqlite3_bulk_step)(statsdb, row_stmt, bulk_stmt, resultset, stats_mysql_global___bind_row); } if (GloMyQPro) { unsigned long long mu = GloMyQPro->get_new_req_conns_count(); - sqlite3_global_stats_row_step(statsdb, row_stmt, "new_req_conns_count", mu); + (*proxy_sqlite3_global_stats_row_step)(statsdb, row_stmt, "new_req_conns_count", mu); } - sqlite3_global_stats_row_step(statsdb, row_stmt, "mysql_listener_paused", admin_proxysql_mysql_paused); - sqlite3_global_stats_row_step(statsdb, row_stmt, "OpenSSL_Version_Num", OpenSSL_version_num()); + (*proxy_sqlite3_global_stats_row_step)(statsdb, row_stmt, "mysql_listener_paused", admin_proxysql_mysql_paused); + (*proxy_sqlite3_global_stats_row_step)(statsdb, row_stmt, "OpenSSL_Version_Num", OpenSSL_version_num()); if (GloMyLogger != nullptr) { @@ -613,7 +613,7 @@ void ProxySQL_Admin::stats___mysql_global() { std::unordered_map metrics = GloMyLogger->getAllMetrics(); for (std::unordered_map::iterator it = metrics.begin(); it != metrics.end(); it++) { string var_name = prefix + it->first; - sqlite3_global_stats_row_step(statsdb, row_stmt, var_name.c_str(), it->second); + (*proxy_sqlite3_global_stats_row_step)(statsdb, row_stmt, var_name.c_str(), it->second); } } @@ -2305,7 +2305,7 @@ void ProxySQL_Admin::stats___mysql_prepared_statements_info() { query32s = "INSERT INTO stats_mysql_prepared_statements_info VALUES " + generate_multi_rows_query(32,9); query32 = (char *)query32s.c_str(); //rc=(*proxy_sqlite3_prepare_v2)(mydb3, query1, -1, &statement1, 0); - //rc=sqlite3_prepare_v2(mydb3, query1, -1, &statement1, 0); + //rc=(*proxy_sqlite3_prepare_v2)(mydb3, query1, -1, &statement1, 0); rc = statsdb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, statsdb); //rc=(*proxy_sqlite3_prepare_v2)(mydb3, query32, -1, &statement32, 0); @@ -2318,30 +2318,30 @@ void ProxySQL_Admin::stats___mysql_prepared_statements_info() { SQLite3_row *r1=*it; int idx=row_idx%32; if (row_idxfields[0])); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_text(statement32, (idx*9)+2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_text(statement32, (idx*9)+3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_text(statement32, (idx*9)+4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_int64(statement32, (idx*9)+5, atoll(r1->fields[5])); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_int64(statement32, (idx*9)+6, atoll(r1->fields[6])); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_int64(statement32, (idx*9)+7, atoll(r1->fields[7])); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_int64(statement32, (idx*9)+8, atoll(r1->fields[8])); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_text(statement32, (idx*9)+9, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*9)+1, atoll(r1->fields[0])); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_text)(statement32, (idx*9)+2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_text)(statement32, (idx*9)+3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_text)(statement32, (idx*9)+4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*9)+5, atoll(r1->fields[5])); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*9)+6, atoll(r1->fields[6])); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*9)+7, atoll(r1->fields[7])); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_int64)(statement32, (idx*9)+8, atoll(r1->fields[8])); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_text)(statement32, (idx*9)+9, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); if (idx==31) { SAFE_SQLITE3_STEP2(statement32); rc=(*proxy_sqlite3_clear_bindings)(statement32); ASSERT_SQLITE_OK(rc, statsdb); rc=(*proxy_sqlite3_reset)(statement32); ASSERT_SQLITE_OK(rc, statsdb); } } else { // single row - rc=sqlite3_bind_int64(statement1, 1, atoll(r1->fields[0])); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_text(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_text(statement1, 3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_text(statement1, 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_int64(statement1, 5, atoll(r1->fields[5])); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_int64(statement1, 6, atoll(r1->fields[6])); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_int64(statement1, 7, atoll(r1->fields[7])); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_int64(statement1, 8, atoll(r1->fields[8])); ASSERT_SQLITE_OK(rc, statsdb); - rc=sqlite3_bind_text(statement1, 9, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_int64)(statement1, 1, atoll(r1->fields[0])); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_text)(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_text)(statement1, 3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_text)(statement1, 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_int64)(statement1, 5, atoll(r1->fields[5])); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_int64)(statement1, 6, atoll(r1->fields[6])); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_int64)(statement1, 7, atoll(r1->fields[7])); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_int64)(statement1, 8, atoll(r1->fields[8])); ASSERT_SQLITE_OK(rc, statsdb); + rc=(*proxy_sqlite3_bind_text)(statement1, 9, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, statsdb); rc=(*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, statsdb); @@ -2372,7 +2372,7 @@ void ProxySQL_Admin::stats___pgsql_prepared_statements_info() { query32s = "INSERT INTO stats_pgsql_prepared_statements_info VALUES " + generate_multi_rows_query(32, 8); query32 = (char*)query32s.c_str(); //rc=(*proxy_sqlite3_prepare_v2)(mydb3, query1, -1, &statement1, 0); - //rc=sqlite3_prepare_v2(mydb3, query1, -1, &statement1, 0); + //rc=(*proxy_sqlite3_prepare_v2)(mydb3, query1, -1, &statement1, 0); rc = statsdb->prepare_v2(query1, &statement1); ASSERT_SQLITE_OK(rc, statsdb); //rc=(*proxy_sqlite3_prepare_v2)(mydb3, query32, -1, &statement32, 0); @@ -2385,28 +2385,28 @@ void ProxySQL_Admin::stats___pgsql_prepared_statements_info() { SQLite3_row* r1 = *it; int idx = row_idx % 32; if (row_idx < max_bulk_row_idx) { // bulk - rc = sqlite3_bind_int64(statement32, (idx * 8) + 1, atoll(r1->fields[0])); ASSERT_SQLITE_OK(rc, statsdb); - rc = sqlite3_bind_text(statement32, (idx * 8) + 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); - rc = sqlite3_bind_text(statement32, (idx * 8) + 3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); - rc = sqlite3_bind_text(statement32, (idx * 8) + 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); - rc = sqlite3_bind_int64(statement32, (idx * 8) + 5, atoll(r1->fields[5])); ASSERT_SQLITE_OK(rc, statsdb); - rc = sqlite3_bind_int64(statement32, (idx * 8) + 6, atoll(r1->fields[6])); ASSERT_SQLITE_OK(rc, statsdb); - rc = sqlite3_bind_int64(statement32, (idx * 8) + 7, atoll(r1->fields[7])); ASSERT_SQLITE_OK(rc, statsdb); - rc = sqlite3_bind_text(statement32, (idx * 8) + 8, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 8) + 1, atoll(r1->fields[0])); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 8) + 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 8) + 3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 8) + 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 8) + 5, atoll(r1->fields[5])); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 8) + 6, atoll(r1->fields[6])); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_int64)(statement32, (idx * 8) + 7, atoll(r1->fields[7])); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_text)(statement32, (idx * 8) + 8, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); if (idx == 31) { SAFE_SQLITE3_STEP2(statement32); rc = (*proxy_sqlite3_clear_bindings)(statement32); ASSERT_SQLITE_OK(rc, statsdb); rc = (*proxy_sqlite3_reset)(statement32); ASSERT_SQLITE_OK(rc, statsdb); } } else { // single row - rc = sqlite3_bind_int64(statement1, 1, atoll(r1->fields[0])); ASSERT_SQLITE_OK(rc, statsdb); - rc = sqlite3_bind_text(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); - rc = sqlite3_bind_text(statement1, 3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); - rc = sqlite3_bind_text(statement1, 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); - rc = sqlite3_bind_int64(statement1, 5, atoll(r1->fields[5])); ASSERT_SQLITE_OK(rc, statsdb); - rc = sqlite3_bind_int64(statement1, 6, atoll(r1->fields[6])); ASSERT_SQLITE_OK(rc, statsdb); - rc = sqlite3_bind_int64(statement1, 7, atoll(r1->fields[7])); ASSERT_SQLITE_OK(rc, statsdb); - rc = sqlite3_bind_text(statement1, 8, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_int64)(statement1, 1, atoll(r1->fields[0])); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_text)(statement1, 2, r1->fields[1], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_text)(statement1, 3, r1->fields[2], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_text)(statement1, 4, r1->fields[3], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_int64)(statement1, 5, atoll(r1->fields[5])); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_int64)(statement1, 6, atoll(r1->fields[6])); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_int64)(statement1, 7, atoll(r1->fields[7])); ASSERT_SQLITE_OK(rc, statsdb); + rc = (*proxy_sqlite3_bind_text)(statement1, 8, r1->fields[4], -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, statsdb); SAFE_SQLITE3_STEP2(statement1); rc = (*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, statsdb); rc = (*proxy_sqlite3_reset)(statement1); ASSERT_SQLITE_OK(rc, statsdb); diff --git a/lib/RAG_Tool_Handler.cpp b/lib/RAG_Tool_Handler.cpp index 5c1ac96f8..d280da3b2 100644 --- a/lib/RAG_Tool_Handler.cpp +++ b/lib/RAG_Tool_Handler.cpp @@ -376,7 +376,7 @@ SQLite3_result* RAG_Tool_Handler::execute_query(const char* query) { if (error) { proxy_error("RAG_Tool_Handler: SQL error: %s\n", error); - proxy_sqlite3_free(error); + proxy_(*proxy_sqlite3_free)(error); return NULL; } @@ -407,7 +407,7 @@ SQLite3_result* RAG_Tool_Handler::execute_parameterized_query(const char* query, // Prepare the statement auto prepare_result = vector_db->prepare_v2(query); if (prepare_result.first != SQLITE_OK) { - proxy_error("RAG_Tool_Handler: Failed to prepare statement: %s\n", sqlite3_errstr(prepare_result.first)); + proxy_error("RAG_Tool_Handler: Failed to prepare statement: %s\n", (*proxy_sqlite3_errstr)(prepare_result.first)); return NULL; } @@ -421,9 +421,9 @@ SQLite3_result* RAG_Tool_Handler::execute_parameterized_query(const char* query, for (const auto& binding : text_bindings) { int position = binding.first; const std::string& value = binding.second; - int result = proxy_sqlite3_bind_text(stmt, position, value.c_str(), -1, SQLITE_STATIC); + int result = proxy_(*proxy_sqlite3_bind_text)(stmt, position, value.c_str(), -1, SQLITE_STATIC); if (result != SQLITE_OK) { - proxy_error("RAG_Tool_Handler: Failed to bind text parameter at position %d: %s\n", position, sqlite3_errstr(result)); + proxy_error("RAG_Tool_Handler: Failed to bind text parameter at position %d: %s\n", position, (*proxy_sqlite3_errstr)(result)); return NULL; } } @@ -432,9 +432,9 @@ SQLite3_result* RAG_Tool_Handler::execute_parameterized_query(const char* query, for (const auto& binding : int_bindings) { int position = binding.first; int value = binding.second; - int result = proxy_sqlite3_bind_int(stmt, position, value); + int result = proxy_(*proxy_sqlite3_bind_int)(stmt, position, value); if (result != SQLITE_OK) { - proxy_error("RAG_Tool_Handler: Failed to bind integer parameter at position %d: %s\n", position, sqlite3_errstr(result)); + proxy_error("RAG_Tool_Handler: Failed to bind integer parameter at position %d: %s\n", position, (*proxy_sqlite3_errstr)(result)); return NULL; } } @@ -447,7 +447,7 @@ SQLite3_result* RAG_Tool_Handler::execute_parameterized_query(const char* query, if (error) { proxy_error("RAG_Tool_Handler: SQL error: %s\n", error); - proxy_sqlite3_free(error); + proxy_(*proxy_sqlite3_free)(error); return NULL; } diff --git a/lib/debug.cpp b/lib/debug.cpp index 0306b65e1..9cfe6d753 100644 --- a/lib/debug.cpp +++ b/lib/debug.cpp @@ -74,7 +74,7 @@ void sync_log_buffer_to_disk(SQLite3DB *db) { rc=(*proxy_sqlite3_bind_text)(statement1, 11, entry.backtrace.c_str(), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, db); SAFE_SQLITE3_STEP2(statement1); rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, db); - // Note: no assert() in proxy_debug_func() after sqlite3_reset() because it is possible that we are in shutdown + // Note: no assert() in proxy_debug_func() after (*proxy_sqlite3_reset)() because it is possible that we are in shutdown rc=(*proxy_sqlite3_reset)(statement1); // ASSERT_SQLITE_OK(rc, db); } db->execute("COMMIT"); diff --git a/lib/proxy_sqlite3_symbols.cpp b/lib/proxy_sqlite3_symbols.cpp index 1b51047d3..b8843edb6 100644 --- a/lib/proxy_sqlite3_symbols.cpp +++ b/lib/proxy_sqlite3_symbols.cpp @@ -19,15 +19,15 @@ int (*proxy_sqlite3_column_bytes)(sqlite3_stmt*, int) = sqlite3_column_bytes; int (*proxy_sqlite3_column_type)(sqlite3_stmt*, int) = sqlite3_column_type; int (*proxy_sqlite3_column_count)(sqlite3_stmt*) = sqlite3_column_count; int (*proxy_sqlite3_column_int)(sqlite3_stmt*, int) = sqlite3_column_int; -sqlite3_int64 (*proxy_sqlite3_column_int64)(sqlite3_stmt*, int) = sqlite3_column_int64; +(*proxy_sqlite3_int64)(*proxy_sqlite3_column_int64)(sqlite3_stmt*, int) = sqlite3_column_int64; double (*proxy_sqlite3_column_double)(sqlite3_stmt*, int) = sqlite3_column_double; -sqlite3_int64 (*proxy_sqlite3_last_insert_rowid)(sqlite3*) = sqlite3_last_insert_rowid; +(*proxy_sqlite3_int64)(*proxy_sqlite3_last_insert_rowid)(sqlite3*) = sqlite3_last_insert_rowid; const char *(*proxy_sqlite3_errstr)(int) = sqlite3_errstr; sqlite3* (*proxy_sqlite3_db_handle)(sqlite3_stmt*) = sqlite3_db_handle; int (*proxy_sqlite3_enable_load_extension)(sqlite3*, int) = sqlite3_enable_load_extension; /* Some platforms may expose sqlite3_enable_load_extension as a macro or different symbol; provide a weak alias to help the linker. */ -extern "C" int proxy_sqlite3_enable_load_extension_alias(sqlite3* db, int onoff) __attribute__((weak)); -int proxy_sqlite3_enable_load_extension_alias(sqlite3* db, int onoff) { return sqlite3_enable_load_extension(db, onoff); } +extern "C" int proxy_(*proxy_sqlite3_enable_load_extension_alias)(sqlite3* db, int onoff) __attribute__((weak)); +int proxy_(*proxy_sqlite3_enable_load_extension_alias)(sqlite3* db, int onoff) { return (*proxy_sqlite3_enable_load_extension)(db, onoff); } int (*proxy_sqlite3_auto_extension)(void(*)(void)) = sqlite3_auto_extension; const char *(*proxy_sqlite3_errmsg)(sqlite3*) = sqlite3_errmsg; int (*proxy_sqlite3_finalize)(sqlite3_stmt *) = sqlite3_finalize; diff --git a/lib/sqlite3db.cpp b/lib/sqlite3db.cpp index 760174299..5d94c5f45 100644 --- a/lib/sqlite3db.cpp +++ b/lib/sqlite3db.cpp @@ -263,7 +263,7 @@ int SQLite3DB::prepare_v2(const char *str, sqlite3_stmt **statement) { } void stmt_deleter_t::operator()(sqlite3_stmt* x) const { - proxy_sqlite3_finalize(x); + proxy_(*proxy_sqlite3_finalize)(x); } std::pair SQLite3DB::prepare_v2(const char* query) { diff --git a/src/SQLite3_Server.cpp b/src/SQLite3_Server.cpp index b00b73328..7043e142e 100644 --- a/src/SQLite3_Server.cpp +++ b/src/SQLite3_Server.cpp @@ -54,7 +54,7 @@ using std::string; #define SAFE_SQLITE3_STEP(_stmt) do {\ do {\ - rc=sqlite3_step(_stmt);\ + rc=(*proxy_sqlite3_step)(_stmt);\ if (rc!=SQLITE_DONE) {\ assert(rc==SQLITE_LOCKED);\ usleep(100);\ @@ -64,7 +64,7 @@ using std::string; #define SAFE_SQLITE3_STEP2(_stmt) do {\ do {\ - rc=sqlite3_step(_stmt);\ + rc=(*proxy_sqlite3_step)(_stmt);\ if (rc==SQLITE_LOCKED || rc==SQLITE_BUSY) {\ usleep(100);\ }\ @@ -1431,7 +1431,7 @@ void SQLite3_Server::populate_galera_table(MySQL_Session *sess) { sqlite3_stmt *statement=NULL; int rc; char *query=(char *)"INSERT INTO HOST_STATUS_GALERA VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11)"; - //rc=sqlite3_prepare_v2(mydb3, query, -1, &statement, 0); + //rc=(*proxy_sqlite3_prepare_v2)(mydb3, query, -1, &statement, 0); rc = sessdb->prepare_v2(query, &statement); ASSERT_SQLITE_OK(rc, sessdb); for (unsigned int i=0; iexecute("COMMIT"); } @@ -1494,15 +1494,15 @@ void bind_query_params( ) { int rc = 0; - rc=sqlite3_bind_text(stmt, 1, server_id.c_str(), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, db); - rc=sqlite3_bind_text(stmt, 2, domain.c_str(), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, db); - rc=sqlite3_bind_text(stmt, 3, session_id.c_str(), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, db); - rc=sqlite3_bind_double(stmt, 4, cpu); ASSERT_SQLITE_OK(rc, db); - rc=sqlite3_bind_text(stmt, 5, lut.c_str(), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, db); - rc=sqlite3_bind_double(stmt, 6, lag_ms); ASSERT_SQLITE_OK(rc, db); + rc=(*proxy_sqlite3_bind_text)(stmt, 1, server_id.c_str(), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, db); + rc=(*proxy_sqlite3_bind_text)(stmt, 2, domain.c_str(), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, db); + rc=(*proxy_sqlite3_bind_text)(stmt, 3, session_id.c_str(), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, db); + rc=(*proxy_sqlite3_bind_double)(stmt, 4, cpu); ASSERT_SQLITE_OK(rc, db); + rc=(*proxy_sqlite3_bind_text)(stmt, 5, lut.c_str(), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, db); + rc=(*proxy_sqlite3_bind_double)(stmt, 6, lag_ms); ASSERT_SQLITE_OK(rc, db); SAFE_SQLITE3_STEP2(stmt); - rc=sqlite3_clear_bindings(stmt); ASSERT_SQLITE_OK(rc, db); - rc=sqlite3_reset(stmt); ASSERT_SQLITE_OK(rc, db); + rc=(*proxy_sqlite3_clear_bindings)(stmt); ASSERT_SQLITE_OK(rc, db); + rc=(*proxy_sqlite3_reset)(stmt); ASSERT_SQLITE_OK(rc, db); } /** @@ -1608,7 +1608,7 @@ void SQLite3_Server::populate_aws_aurora_table(MySQL_Session *sess, uint32_t whg } } - sqlite3_finalize(stmt); + (*proxy_sqlite3_finalize)(stmt); delete resultset; } else { // We just re-generate deterministic 'SESSION_IDS', preserving 'MASTER_SESSION_ID' values: @@ -1684,7 +1684,7 @@ void SQLite3_Server::populate_aws_aurora_table(MySQL_Session *sess, uint32_t whg float cpu = get_rand_cpu(); bind_query_params(sessdb, stmt, serverid, aurora_domain, sessionid, cpu, lut, lag_ms); } - sqlite3_finalize(stmt); + (*proxy_sqlite3_finalize)(stmt); #endif // TEST_AURORA_RANDOM } #endif // TEST_AURORA