TkN 2.7
Toolkit for Nuclei
Loading...
Searching...
No Matches
tkdatabase.cpp
1/********************************************************************************
2 * Copyright (c) : Université de Lyon 1, CNRS/IN2P3, UMR5822, *
3 * IP2I, F-69622 Villeurbanne Cedex, France *
4 * Normandie Université, ENSICAEN, UNICAEN, CNRS/IN2P3, *
5 * LPC Caen, F-14000 Caen, France *
6 * Contibutor(s) : *
7 * Jérémie Dudouet jeremie.dudouet@cnrs.fr [2020] *
8 * Diego Gruyer diego.gruyer@cnrs.fr [2020] *
9 * *
10 * Licensed under the MIT License <http://opensource.org/licenses/MIT>. *
11 * SPDX-License-Identifier: MIT *
12 ********************************************************************************/
13
14#include "tkdatabase.h"
15
16#include <algorithm>
17
18#include "tksystem.h"
19
20namespace tkn {
30}
31
32using namespace tkn;
33
34tkdatabase *tkdatabase::g_database = nullptr;
35
37{
38 if(g_database) return g_database;
39
40 std::lock_guard<std::recursive_mutex> lock(get_mutex());
41
42 if ( g_database == nullptr ) {
43 g_database = new tkdatabase();
44 }
45
46 return g_database;
47}
48
49tkdatabase::tkdatabase(bool opening_db)
50{
51 std::lock_guard<std::recursive_mutex> lock(get_mutex());
52
53 if(g_database == nullptr && opening_db) open(tkstring::Form("%s/TkN.db", TKN_DB_DIR));
54}
55
57{
58 std::lock_guard<std::recursive_mutex> lock(get_mutex());
59 if(g_database == this) g_database = nullptr;
60}
61
62sqlite3* tkdatabase::open(tkstring _db_name, tkstring _option)
63{
64 glog.set_class("database");
65 glog.set_method(tkstring::Form("open(%s,%s)",_db_name.data(),_option.data()));
66
67 if(!_db_name.ends_with(".db")) _db_name.append(".db");
68
69 fName = _db_name;
70
71 _option.to_upper();
72
73 if(_option.equal_to("RECREATE")) {
74 if(gsystem->exists(fName)) {
75 glog << warning << "Existing database '" << _db_name << "' will be deleted and recreated." << do_endl;
76 gsystem->remove_file(fName,true);
77 }
78 fMode = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
79 }
80 else if(_option.equal_to("NEW")||_option.equal_to("CREATE")) fMode = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
81 else if(_option.equal_to("OPEN")) fMode = SQLITE_OPEN_READONLY;
82 else if(_option.equal_to("UPDATE")) fMode = SQLITE_OPEN_READWRITE;
83 else {
84 glog << warning_v << "'" << _option << "' option not suported." << do_endl;
85 glog << warning_v << "'OPEN' option used by default..." << do_endl;
86 fMode = SQLITE_OPEN_READONLY;
87 }
88
89 sqlite3* db;
90 if(sqlite3_open_v2(fName.data(), &db,fMode,nullptr) != SQLITE_OK) {
91 glog << error_v << "can't open database: '" << sqlite3_errmsg(db) << "'" << do_endl;
92 glog << info << "use tkn-db-update to download the database" << do_endl;
93 sqlite3_close(db);
94 glog.clear();
95 return nullptr;
96 }
97
98 fFullName = gsystem->get_system_command_output(tkstring::form("ls -l %s",fName.data()));
99 fFullName = fFullName.tokenize(" ").back();
100 fFullName.remove_all("\n");
101 fFullName = fFullName.tokenize("/").back();
102
103 fDataBase = db;
104 load_tables();
105 load_views();
106
107 exec_sql("PRAGMA synchronous = OFF");
108 exec_sql("PRAGMA temp_store = MEMORY");
109 exec_sql("PRAGMA mmap_size = 30000000000");
110 exec_sql("PRAGMA page_size = 32768 ");
111
112 glog.clear();
113 return db;
114}
115
117{
118 sqlite3_close(fDataBase);
119}
120
122{
123 const char *sql = "SELECT name FROM sqlite_master WHERE type='table'";
124 sqlite3_stmt* stmt;
125 sqlite3_prepare_v2(fDataBase, sql, -1, &stmt, nullptr);
126
127 while(sqlite3_step(stmt) == SQLITE_ROW) {
128 tkstring table_name(sqlite3_column_text(stmt, 0));
129 fTables.insert(std::make_pair(table_name,tkdb_table(table_name.data(),fDataBase)));
130 fTables[table_name.data()].load();
131 }
132 sqlite3_finalize(stmt);
133}
134
136{
137 const char *sql = "SELECT name FROM sqlite_master WHERE type='view'";
138 sqlite3_stmt* stmt;
139 sqlite3_prepare_v2(fDataBase, sql, -1, &stmt, nullptr);
140
141 while(sqlite3_step(stmt) == SQLITE_ROW) {
142 tkstring table_name(sqlite3_column_text(stmt, 0));
143 fViews.push_back(table_name);
144 }
145 sqlite3_finalize(stmt);
146}
147
149{
150 fTables.insert(std::make_pair(_table.get_name(),_table));
151}
152
153bool tkdatabase::has_table(const tkstring &_table_name)
154{
155 return fTables.count(_table_name)>0;
156}
157
158bool tkdatabase::has_view(const tkstring &_table_name)
159{
160 return std::count(fViews.begin(), fViews.end(), _table_name)>0;
161}
162
164{
165 fTables.insert(std::make_pair(_table_name,tkdb_table(_table_name.data(),fDataBase)));
166 return fTables[_table_name];
167}
168
170{
171 tkstring sql = tkstring::form("DROP TABLE %s ", _table_name.data());
172 exec_sql(sql.data());
173 fTables.erase(_table_name.data());
174}
175
177{
178 return &fTables[_table_name.data()];
179}
180
181void tkdatabase::print(const tkstring &_properties, const tkstring &_opt)
182{
183 for(auto &table : fTables){
184 for(auto &col : table.second.get_columns()) {
185 if(_properties.contains(col.first.data())||_properties.equal_to("*")) {
186 if(_opt.contains("notnull")&&!strcmp(col.second.get_value().data(),"")) continue;
187 glog << "|";
188 glog << col.first << "=" << col.second.get_value();
189 }
190 }
191 }
192 glog << do_endl;
193}
194
195void tkdatabase::begin(tkstring _selection, tkstring _from, tkstring _condition, tkstring _loop_name, tkstring _extra_cmd)
196{
197 glog.set_class("database");
198 glog.set_method(tkstring::Form("begin(%s,%s,%s,%s,%s)",_selection.data(),_from.data(),_condition.data(),_loop_name.data(),_extra_cmd.data()));
199
200 if(fSQLStatement.count(_loop_name)) {
201 glog << warning_v << "Previous sql statement not yet closed. Closing in to start new statement..." << do_endl;
202 end(_loop_name);
203 }
204
205 if(!_condition.empty()) _condition.prepend("where ");
206
207 sqlite3_stmt* sqlstm = nullptr;
208 int rc = sqlite3_prepare_v2(fDataBase, tkstring::form("select %s from %s %s",_selection.data(),_from.data(),_condition.data(),_extra_cmd.data()), -1, &sqlstm, nullptr);
209 if( rc!=SQLITE_OK ) {
210 glog << error_v << "SQL error: " << sqlite3_errmsg(fDataBase) << do_endl;
211 glog << tkstring::form("select %s from %s %s",_selection.data(),_from.data(),_condition.data()) << do_endl;
212 if(sqlstm) sqlite3_finalize(sqlstm);
213 sqlite3_free(nullptr);
214 }
215 else {
216 fSQLStatement.emplace(_loop_name, sqlstm);
217 fReading = true;
218 }
219
220 glog.clear();
221}
222
223bool tkdatabase::next(const tkstring &_loop_name)
224{
225 glog.set_class("database");
226 glog.set_method("next()");
227
228 if(!fSQLStatement.count(_loop_name)) {
229 glog << error_v << "No sql statement name "<< _loop_name << " prepared, please call begin() to prepare it " << do_endl;
230 glog.clear();
231 return false;
232 }
233
234 int ret_code = sqlite3_step(fSQLStatement[_loop_name]);
235 if(ret_code == SQLITE_ROW) {
236 int cols = sqlite3_column_count(fSQLStatement[_loop_name]);
237 for (int i=0; i<cols; i++) {
238 const unsigned char* tmp = sqlite3_column_text(fSQLStatement[_loop_name], i);
239 const char* col_name = sqlite3_column_name(fSQLStatement[_loop_name], i);
240 for(auto &table : fTables){
241 if(table.second.has_column(col_name)) {
242 if(tmp == nullptr)
243 table.second[col_name].set_value_str("");
244 else
245 table.second[col_name].set_value_str(reinterpret_cast<const char*>(tmp));
246 }
247 }
248 }
249 glog.clear();
250 return true;
251 }
252 end(_loop_name);
253 glog.clear();
254 return false;
255}
256
257void tkdatabase::end(const tkstring &_loop_name)
258{
259 glog.set_class("database");
260 glog.set_method("end()");
261 if(!fSQLStatement.count(_loop_name)) {
262 glog << error_v << "No sql statement prepared to close..." << do_endl;
263 glog.clear();
264 return;
265 }
266 sqlite3_finalize(fSQLStatement[_loop_name]);
267 fReading = false;
268 fSQLStatement.erase(_loop_name);
269 for(auto &table : fTables) table.second.reset_column_values();
270 glog.clear();
271}
272
273int tkdatabase::count(const tkstring &_from, const tkstring &_condition)
274{
275 int counts = 0;
276 begin("*",_from,_condition,"count");
277 while(next("count")) counts++;
278 return counts;
279}
280
282{
283 glog.set_class("database");
284 glog.set_method(tkstring::Form("get_value(%s,%s,%s)",_selection.data(),_from.data(),_condition.data()));
285
286 if(_selection.contains(",")) glog << error_v << "Selection should contains only one column name !" << do_endl;
287 _condition += " LIMIT 1";
288
289 begin(_selection,_from,_condition,"get_value");
290 if(next("get_value")) {
291 tkstring val = "";
292 for(auto &table : fTables) if(table.second.has_column(_selection)) val = table.second[_selection.data()].get_value();
293 if(next("get_value")) glog << warning_v << "More than one entry corresponding to this criteria : only first value returned" << do_endl;
294 if(fSQLStatement.count("get_value")) end("get_value");
295 glog.clear();
296 return val;
297 }
298
299 glog << error_v << "No entry corresponding to the asked criteria" << do_endl;
300 glog.clear();
301 return "";
302}
303
304int tkdatabase::exec_sql(const char *_cmd)
305{
306 char *zErrMsg = nullptr;
307 int rc = sqlite3_exec(fDataBase, _cmd, nullptr, nullptr, &zErrMsg);
308
309 if( rc != SQLITE_OK ) {
310 glog << error << "SQL error: " << zErrMsg << " while excuting command: " << _cmd << do_endl;
311 sqlite3_free(zErrMsg);
312 }
313 else {}
314 return rc;
315}
316
317#ifdef HAS_ROOT
319ClassImp(tkdatabase);
320#endif
Interface to the sqlite database.
Definition tkdatabase.h:34
int count(const tkstring &_from, const tkstring &_condition="")
resets column values and ends the select statement
virtual ~tkdatabase()
void end(const tkstring &_loop_name="default")
reads the next entry coresponding to the select statement and fills columns
void remove_table(tkstring _table_name)
void add_table(tkdb_table &_table)
void begin(tkstring _selection, tkstring _from, tkstring _condition="", tkstring _loop_name="default", tkstring _extra_cmd="")
tkstring get_value(tkstring _selection, tkstring _from, tkstring _condition="")
tkdb_table & new_table(tkstring _table_name)
sqlite3 * open(tkstring _db, tkstring _option="OPEN")
bool has_view(const tkstring &_table_name)
tkdatabase(bool opening_db=true)
void print(const tkstring &_properties="", const tkstring &_opt="")
int exec_sql(const char *_cmd)
returns the first value for selection
bool has_table(const tkstring &_table_name)
tkdb_table * get_table(tkstring _table_name)
bool next(const tkstring &_loop_name="default")
executes the select statement
static tkdatabase * the_database()
Representaiton of a sqlite data table.
Definition tkdb_table.h:29
tkstring get_name()
Definition tkdb_table.h:93
std::string with usefull tricks from TString (ROOT) and KVString (KaliVeda) and more....
Definition tkstring.h:32
static const char * form(const char *_format,...)
Definition tkstring.cpp:452
std::vector< tkstring > tokenize(const tkstring &_delim=" ") const
Create a vector of string separated by at least one delimiter.
Definition tkstring.cpp:275
static tkstring Form(const char *_format,...)
Definition tkstring.cpp:366
bool ends_with(const char *_s, ECaseCompare _cmp=kExact) const
Definition tkstring.cpp:262
bool equal_to(const char *_s, ECaseCompare _cmp=kExact) const
Returns true if the string and _s are identical.
Definition tkstring.cpp:255
bool contains(const char *_pat, ECaseCompare _cmp=kExact) const
Definition tkstring.h:175
tkstring & prepend(const tkstring &_st)
Definition tkstring.h:202
tkstring & append(const tkstring &_st)
Definition tkstring.h:205
tkstring & to_upper()
Change all letters to upper case.
Definition tkstring.cpp:86
Definition tklog.cpp:16
tklog & error_v(tklog &log)
Definition tklog.h:407
tklog & info(tklog &log)
Definition tklog.h:313
tklog & warning_v(tklog &log)
Definition tklog.h:386
tklog & error(tklog &log)
Definition tklog.h:344
tklog & do_endl(tklog &log)
Definition tklog.h:212
tklog & warning(tklog &log)
Definition tklog.h:331