flexiblesusy is hosted by Hepforge, IPPP Durham
FlexibleSUSY
database.cpp
Go to the documentation of this file.
1// ====================================================================
2// This file is part of FlexibleSUSY.
3//
4// FlexibleSUSY is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published
6// by the Free Software Foundation, either version 3 of the License,
7// or (at your option) any later version.
8//
9// FlexibleSUSY is distributed in the hope that it will be useful, but
10// WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with FlexibleSUSY. If not, see
16// <http://www.gnu.org/licenses/>.
17// ====================================================================
18
19#include "database.hpp"
20#include "error.hpp"
21#include "logger.hpp"
22#include "config.h"
23#include "string_format.hpp"
24
25#include <cstddef>
26#include <limits>
27#include <sstream>
28#include <string>
29#include <iomanip>
30
31#ifdef ENABLE_SQLITE
32
33#include <sqlite3.h>
34
35namespace flexiblesusy {
36namespace database {
37
38namespace {
39
40double to_double(const std::string& str)
41{
42 double d = 0.0;
43
44 try {
45 d = std::stod(str);
46 } catch (std::exception& e) {
47 throw ReadError(e.what());
48 }
49
50 return d;
51}
52
53} // anonymous namespace
54
55class SQLiteReadError : Error {
56public:
57 explicit SQLiteReadError(const std::string& msg) : Error(msg) {}
58 explicit SQLiteReadError(const char* msg) : Error(msg) {}
59 virtual ~SQLiteReadError() = default;
60};
61
69sqlite3* open(const std::string& file_name)
70{
71 sqlite3* db = nullptr;
72
73 const int rc = sqlite3_open(file_name.c_str(), &db);
74
75 if (rc) {
76 throw SQLiteReadError("Cannot open sqlite3 database file "
77 + file_name + ": " + sqlite3_errmsg(db));
78 }
79
80 return db;
81}
82
94int extract_callback(void* data, int argc, char** argv, char** col_name)
95{
96 auto values = static_cast<Eigen::ArrayXd*>(data);
97 values->conservativeResize(argc);
98
99 for (int i = 0; i < argc; i++) {
100 (*values)(i) = to_double(argv[i]);
101 VERBOSE_MSG(col_name[i] << " = " << argv[i]);
102 }
103
104 return 0;
105}
106
107Database::Database(const std::string& file_name)
108 : db(open(file_name))
109{
110}
111
112Database::~Database()
113{
114 sqlite3_close(db);
115}
116
125void Database::insert(
126 const std::string& table_name, const std::vector<std::string>& names,
127 const Eigen::ArrayXd& data)
128{
129 const std::size_t number_of_elements = data.rows();
130
131 if (names.size() != number_of_elements) {
132 ERROR("number of column names (" << names.size() <<
133 ") does not match vector size (" << number_of_elements << ")!");
134 return;
135 }
136
137 create_table<double>(table_name, names);
138
139 std::string sql("INSERT INTO " + table_name + " (");
140
141 for (std::size_t i = 0; i < number_of_elements; i++) {
142 sql += '"' + names[i] + '"';
143 if (i + 1 != number_of_elements)
144 sql += ',';
145 }
146
147 sql += ") VALUES (";
148
149 for (std::size_t i = 0; i < number_of_elements; i++) {
150 sql += flexiblesusy::to_string(data[i]);
151 if (i + 1 != number_of_elements)
152 sql += ',';
153 }
154
155 sql += ");";
156
157 execute("PRAGMA synchronous = OFF;");
158 execute(sql);
159}
160
168Eigen::ArrayXd Database::extract(const std::string& table_name, long long row)
169{
170 Eigen::ArrayXd values;
171 const std::string sql =
172 (row >= 0 ?
173 "SELECT * FROM " + table_name + " LIMIT 1 OFFSET "
174 + flexiblesusy::to_string(row) + ";" :
175 "SELECT * FROM " + table_name + " WHERE ROWID = (SELECT MAX(ROWID) - "
176 + flexiblesusy::to_string(std::abs(row + 1)) + " FROM " + table_name + ");");
177
178 execute(sql, extract_callback, static_cast<void*>(&values));
179
180 return values;
181}
182
190template <typename T>
191void Database::create_table(
192 const std::string& table_name, const std::vector<std::string>& names)
193{
194 const std::size_t number_of_elements = names.size();
195 std::string sql("CREATE TABLE IF NOT EXISTS " + table_name + " (");
196
197 for (std::size_t i = 0; i < number_of_elements; i++) {
198 sql += '"' + names[i] + R"(" REAL)";
199 if (i + 1 != number_of_elements)
200 sql += ',';
201 }
202
203 sql += ");";
204
205 execute(sql);
206}
207
213void Database::execute(const std::string& cmd)
214{
215 char* zErrMsg = nullptr;
216 const int rc = sqlite3_exec(db, cmd.c_str(), nullptr, nullptr, &zErrMsg);
217
218 if (rc != SQLITE_OK) {
219 ERROR("SQL error while executing command \"" << cmd << "\": " << zErrMsg);
220 sqlite3_free(zErrMsg);
221 } else {
222 VERBOSE_MSG("SQL command \"" << cmd << "\" executed successfully");
223 }
224}
225
233void Database::execute(const std::string& cmd, TCallback callback, void* data)
234{
235 char* zErrMsg = nullptr;
236 const int rc = sqlite3_exec(db, cmd.c_str(), callback, data, &zErrMsg);
237
238 if (rc != SQLITE_OK) {
239 ERROR("SQL error while executing command \"" << cmd << "\": " << zErrMsg);
240 sqlite3_free(zErrMsg);
241 } else {
242 VERBOSE_MSG("SQL command \"" << cmd << "\" executed successfully");
243 }
244}
245
246} // namespace database
247} // namespace flexiblesusy
248
249#else
250
251namespace flexiblesusy {
252namespace database {
253
255public:
256 explicit DisabledSQLiteError(const std::string& msg) : Error(msg) {}
257 explicit DisabledSQLiteError(const char* msg) : Error(msg) {}
258 virtual ~DisabledSQLiteError() = default;
259};
260
261Database::Database(const std::string&)
262{
263}
264
266{
267}
268
270 const std::string&, const std::vector<std::string>&, const Eigen::ArrayXd&)
271{
272 throw DisabledSQLiteError("Cannot call insert(), because SQLite support is disabled.");
273}
274
275Eigen::ArrayXd Database::extract(const std::string&, long long)
276{
277 throw DisabledSQLiteError("Cannot call extract(), because SQLite support is disabled.");
278}
279
280template <typename T>
281void Database::create_table(const std::string&, const std::vector<std::string>&)
282{
283}
284
285void Database::execute(const std::string&) {}
286
287void Database::execute(const std::string&, TCallback, void*) {}
288
289} // namespace database
290} // namespace flexiblesusy
291
292#endif
void execute(const std::string &)
Definition: database.cpp:285
void create_table(const std::string &, const std::vector< std::string > &)
Definition: database.cpp:281
Database(const std::string &file_name)
Definition: database.cpp:261
int(*)(void *, int, char **, char **) TCallback
Definition: database.hpp:42
Eigen::ArrayXd extract(const std::string &, long long)
extract a row of doubles from a table
Definition: database.cpp:275
void insert(const std::string &, const std::vector< std::string > &, const Eigen::ArrayXd &)
insert a row of doubles into a table
Definition: database.cpp:269
DisabledSQLiteError(const std::string &msg)
Definition: database.cpp:256
#define ERROR(msg)
Definition: logger.hpp:65
#define VERBOSE_MSG(msg)
Definition: logger.hpp:57
std::string to_string(char a)
double to_double(const char *s)
data
Definition: scan_HSSUSY.m:46