From 9a81ab42220990531704c8c994819894e6510f95 Mon Sep 17 00:00:00 2001 From: Horst Schirmeier Date: Mon, 5 May 2014 09:40:14 +0200 Subject: [PATCH] Database: more flexible get_variants() This change moves prune-trace's --variants-exclude / --benchmarks-exclude capabilities to Database::get_variants() to make it available to all users. Change-Id: Icbc6bb1a3ae7c846d2de40b881f47a9cc1ed7bbf --- src/core/util/Database.cc | 89 ++++++++++++++++++++++++-------- src/core/util/Database.hpp | 13 +++++ tools/prune-trace/BasicPruner.cc | 13 +++-- tools/prune-trace/Pruner.cc | 39 ++++++-------- tools/prune-trace/Pruner.hpp | 3 +- 5 files changed, 106 insertions(+), 51 deletions(-) diff --git a/src/core/util/Database.cc b/src/core/util/Database.cc index 398b0299..a5a64a17 100644 --- a/src/core/util/Database.cc +++ b/src/core/util/Database.cc @@ -141,34 +141,81 @@ my_ulonglong Database::insert_id() return mysql_insert_id(handle); } -std::vector Database::get_variants(const std::string &variant, const std::string &benchmark) { - std::vector result; - +bool Database::create_variants_table() +{ if (!query("CREATE TABLE IF NOT EXISTS variant (" - " id int(11) NOT NULL AUTO_INCREMENT," - " variant varchar(255) NOT NULL," - " benchmark varchar(255) NOT NULL," - " PRIMARY KEY (id)," - "UNIQUE KEY variant (variant,benchmark)) ENGINE=MyISAM")) { + " id int(11) NOT NULL AUTO_INCREMENT," + " variant varchar(255) NOT NULL," + " benchmark varchar(255) NOT NULL," + " PRIMARY KEY (id)," + "UNIQUE KEY variant (variant,benchmark)) ENGINE=MyISAM")) { + return false; + } + return true; +} + +std::vector Database::get_variants(const std::string &variant, const std::string &benchmark) +{ + std::vector variants; + variants.push_back(variant); + std::vector benchmarks; + benchmarks.push_back(benchmark); + std::vector dummy; + + return get_variants(variants, dummy, benchmarks, dummy); +} + +std::vector Database::get_variants( + const std::vector& variants, + const std::vector& variants_exclude, + const std::vector& benchmarks, + const std::vector& benchmarks_exclude) +{ + std::vector result; + std::stringstream ss; + + // make sure variant table exists + if (!create_variants_table()) { return result; } - std::stringstream ss; - // FIXME SQL injection possible - ss << "SELECT id, variant, benchmark FROM variant WHERE variant LIKE '" << variant << "' AND benchmark LIKE '" << benchmark << "'"; - MYSQL_RES *variant_id_res = query(ss.str().c_str(), true); + // FIXME string escaping + ss << "SELECT id, variant, benchmark FROM variant WHERE "; + ss << "("; + for (std::vector::const_iterator it = variants.begin(); + it != variants.end(); ++it) { + ss << "variant LIKE '" << *it << "' OR "; + } + ss << "0) AND ("; + for (std::vector::const_iterator it = benchmarks.begin(); + it != benchmarks.end(); ++it) { + ss << "benchmark LIKE '" << *it << "' OR "; + } + // dummy terminator to avoid special cases in query construction above + ss << "0) AND NOT ("; + for (std::vector::const_iterator it = variants_exclude.begin(); + it != variants_exclude.end(); ++it) { + ss << "variant LIKE '" << *it << "' OR "; + } + for (std::vector::const_iterator it = benchmarks_exclude.begin(); + it != benchmarks_exclude.end(); ++it) { + ss << "benchmark LIKE '" << *it << "' OR "; + } + // dummy terminator to avoid special cases in query construction above + ss << "0)"; + MYSQL_RES *variant_id_res = query(ss.str().c_str(), true); if (!variant_id_res) { return result; - } else if (mysql_num_rows(variant_id_res)) { - for (unsigned int i = 0; i < mysql_num_rows(variant_id_res); ++i) { - MYSQL_ROW row = mysql_fetch_row(variant_id_res); - Variant var; - var.id = atoi(row[0]); - var.variant = std::string(row[1]); - var.benchmark = std::string(row[2]); - result.push_back(var); - } + } + + MYSQL_ROW row; + while ((row = mysql_fetch_row(variant_id_res))) { + Variant var; + var.id = atoi(row[0]); + var.variant = row[1]; + var.benchmark = row[2]; + result.push_back(var); } return result; diff --git a/src/core/util/Database.hpp b/src/core/util/Database.hpp index 626b9eaa..3a1ed817 100644 --- a/src/core/util/Database.hpp +++ b/src/core/util/Database.hpp @@ -54,6 +54,16 @@ namespace fail { */ std::vector get_variants(const std::string &variant, const std::string &benchmark); + /** + * Get all variants that fit one of the variant, one of the benchmark, + * and none of the variant/benchmark exclude patterns (will be queried + * with SQL LIKE). + */ + std::vector get_variants( + const std::vector& variants, + const std::vector& variants_exclude, + const std::vector& benchmarks, + const std::vector& benchmarks_exclude); /** * Get the fault space pruning method id for a specific @@ -113,6 +123,9 @@ namespace fail { */ static void cmdline_setup(); static Database * cmdline_connect(); + + private: + bool create_variants_table(); }; } diff --git a/tools/prune-trace/BasicPruner.cc b/tools/prune-trace/BasicPruner.cc index 9c77b988..5fbc1d9d 100644 --- a/tools/prune-trace/BasicPruner.cc +++ b/tools/prune-trace/BasicPruner.cc @@ -19,22 +19,21 @@ bool BasicPruner::prune_all() { "SELECT 0, variant_id, instr2, " << injection_instr << ", " << injection_instr_absolute << ", " " data_address, width, " << m_method_id << " " "FROM trace " - "WHERE variant_id IN (" << m_variant_id_query << ") AND accesstype = 'R'"; + "WHERE variant_id IN (" << m_variants_sql << ") AND accesstype = 'R'"; if (!db->query(ss.str().c_str())) return false; ss.str(""); int rows = db->affected_rows(); // for each variant: - MYSQL_RES *res = db->query(m_variant_id_query.c_str(), true); - MYSQL_ROW row; - while ((row = mysql_fetch_row(res))) { + for (std::vector::const_iterator it = m_variants.begin(); + it != m_variants.end(); ++it) { // single entry for known outcome (write access) ss << "INSERT INTO fsppilot (known_outcome, variant_id, instr2, injection_instr, injection_instr_absolute, data_address, data_width, fspmethod_id) " "SELECT 1, variant_id, instr2, " << injection_instr << ", " << injection_instr_absolute << ", " " data_address, width, " << m_method_id << " " "FROM trace " - "WHERE variant_id = " << row[0] << " AND accesstype = 'W' " + "WHERE variant_id = " << it->id << " AND accesstype = 'W' " "ORDER BY instr2 ASC " "LIMIT 1"; if (!db->query(ss.str().c_str())) return false; @@ -50,7 +49,7 @@ bool BasicPruner::prune_all() { << "JOIN trace t ON t.variant_id = p.variant_id AND t.instr2 = p.instr2" << " AND t.data_address = p.data_address " << "WHERE known_outcome = 0 AND p.fspmethod_id = " << m_method_id << " " - << "AND p.variant_id IN (" << m_variant_id_query << ")"; + << "AND p.variant_id IN (" << m_variants_sql << ")"; if (!db->query(ss.str().c_str())) return false; ss.str(""); @@ -61,7 +60,7 @@ bool BasicPruner::prune_all() { "FROM fsppilot p " "JOIN trace t " "ON t.variant_id = p.variant_id AND p.fspmethod_id = " << m_method_id << " AND p.known_outcome = 1 " - "WHERE t.variant_id IN (" << m_variant_id_query << ") AND t.accesstype = 'W'"; + "WHERE t.variant_id IN (" << m_variants_sql << ") AND t.accesstype = 'W'"; if (!db->query(ss.str().c_str())) return false; ss.str(""); rows += db->affected_rows(); diff --git a/tools/prune-trace/Pruner.cc b/tools/prune-trace/Pruner.cc index 4066461d..644a9d0b 100644 --- a/tools/prune-trace/Pruner.cc +++ b/tools/prune-trace/Pruner.cc @@ -15,29 +15,24 @@ bool Pruner::init(fail::Database *db, const std::vector& benchmarks_exclude) { this->db = db; - std::stringstream ss; - // FIXME string escaping - ss << "SELECT id FROM variant WHERE "; - for (std::vector::const_iterator it = variants.begin(); - it != variants.end(); ++it) { - ss << "variant LIKE '" << *it << "' AND "; + m_variants = db->get_variants( + variants, variants_exclude, + benchmarks, benchmarks_exclude); + if (m_variants.size() == 0) { + LOG << "no variants found, nothing to do" << std::endl; + return false; } - for (std::vector::const_iterator it = variants_exclude.begin(); - it != variants_exclude.end(); ++it) { - ss << "variant NOT LIKE '" << *it << "' AND "; + + std::stringstream ss; + for (std::vector::const_iterator it = m_variants.begin(); + it != m_variants.end(); ++it) { + if (it != m_variants.begin()) { + ss << ","; + } + ss << it->id; } - for (std::vector::const_iterator it = benchmarks.begin(); - it != benchmarks.end(); ++it) { - ss << "benchmark LIKE '" << *it << "' AND "; - } - for (std::vector::const_iterator it = benchmarks_exclude.begin(); - it != benchmarks_exclude.end(); ++it) { - ss << "benchmark NOT LIKE '" << *it << "' AND "; - } - // dummy terminator to avoid special cases in query construction above - ss << "1"; - m_variant_id_query = ss.str(); + m_variants_sql = ss.str(); if (!(m_method_id = db->get_fspmethod_id(method_name()))) { return false; @@ -79,13 +74,13 @@ bool Pruner::create_database() { bool Pruner::clear_database() { std::stringstream ss; - ss << "DELETE FROM fsppilot WHERE variant_id IN (" << m_variant_id_query + ss << "DELETE FROM fsppilot WHERE variant_id IN (" << m_variants_sql << ") AND fspmethod_id = " << m_method_id; bool ret = (bool) db->query(ss.str().c_str()); LOG << "deleted " << db->affected_rows() << " rows from fsppilot table" << std::endl; ss.str(""); - ss << "DELETE FROM fspgroup WHERE variant_id IN (" << m_variant_id_query + ss << "DELETE FROM fspgroup WHERE variant_id IN (" << m_variants_sql << ") AND fspmethod_id = " << m_method_id; ret = ret && (bool) db->query(ss.str().c_str()); LOG << "deleted " << db->affected_rows() << " rows from fspgroup table" << std::endl; diff --git a/tools/prune-trace/Pruner.hpp b/tools/prune-trace/Pruner.hpp index dfa29f20..e6e1f5dc 100644 --- a/tools/prune-trace/Pruner.hpp +++ b/tools/prune-trace/Pruner.hpp @@ -8,8 +8,9 @@ class Pruner { protected: int m_method_id; - std::string m_variant_id_query; fail::Database *db; + std::vector m_variants; + std::string m_variants_sql; public: bool init(fail::Database *db,