TkN 2.4
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/databases/TkN.db",TKN_SYS));
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(TKN_SYS == nullptr) {
68 glog << error_v << " TKN_SYS environment variable not defined, cannot find the repository of the data bases !" << do_endl;
69 glog.clear();
70 return nullptr;
71 }
72
73 if(!_db_name.ends_with(".db")) _db_name.append(".db");
74
75 fName = _db_name;
76
77 _option.to_upper();
78
79 if(_option.equal_to("RECREATE")) {
80 if(gsystem->exists(fName)) {
81 glog << warning << "Existing database '" << _db_name << "' will be deleted and recreated." << do_endl;
82 gsystem->remove_file(fName,true);
83 }
84 fMode = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
85 }
86 else if(_option.equal_to("NEW")||_option.equal_to("CREATE")) fMode = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
87 else if(_option.equal_to("OPEN")) fMode = SQLITE_OPEN_READONLY;
88 else if(_option.equal_to("UPDATE")) fMode = SQLITE_OPEN_READWRITE;
89 else {
90 glog << warning_v << "'" << _option << "' option not suported." << do_endl;
91 glog << warning_v << "'OPEN' option used by default..." << do_endl;
92 fMode = SQLITE_OPEN_READONLY;
93 }
94
95 sqlite3* db;
96 if(sqlite3_open_v2(fName.data(), &db,fMode,nullptr) != SQLITE_OK) {
97 glog << error_v << "can't open database: '" << sqlite3_errmsg(db) << "'" << do_endl;
98 glog << info << "use tkn-db-update to download the database" << do_endl;
99 sqlite3_close(db);
100 glog.clear();
101 return nullptr;
102 }
103
104 fFullName = gsystem->get_system_command_output(tkstring::form("ls -l %s",fName.data()));
105 fFullName = fFullName.tokenize(" ").back();
106 fFullName.remove_all("\n");
107 fFullName = fFullName.tokenize("/").back();
108
109 fDataBase = db;
110 load_tables();
111 load_views();
112
113 exec_sql("PRAGMA synchronous = OFF");
114 exec_sql("PRAGMA temp_store = MEMORY");
115 exec_sql("PRAGMA mmap_size = 30000000000");
116 exec_sql("PRAGMA page_size = 32768 ");
117
118 glog.clear();
119 return db;
120}
121
123{
124 sqlite3_close(fDataBase);
125}
126
128{
129 const char *sql = "SELECT name FROM sqlite_master WHERE type='table'";
130 sqlite3_stmt* stmt;
131 sqlite3_prepare_v2(fDataBase, sql, -1, &stmt, nullptr);
132
133 while(sqlite3_step(stmt) == SQLITE_ROW) {
134 tkstring table_name(sqlite3_column_text(stmt, 0));
135 fTables.insert(std::make_pair(table_name,tkdb_table(table_name.data(),fDataBase)));
136 fTables[table_name.data()].load();
137 }
138 sqlite3_finalize(stmt);
139}
140
142{
143 const char *sql = "SELECT name FROM sqlite_master WHERE type='view'";
144 sqlite3_stmt* stmt;
145 sqlite3_prepare_v2(fDataBase, sql, -1, &stmt, nullptr);
146
147 while(sqlite3_step(stmt) == SQLITE_ROW) {
148 tkstring table_name(sqlite3_column_text(stmt, 0));
149 fViews.push_back(table_name);
150 }
151 sqlite3_finalize(stmt);
152}
153
155{
156 fTables.insert(std::make_pair(_table.get_name(),_table));
157}
158
159bool tkdatabase::has_table(const tkstring &_table_name)
160{
161 return fTables.count(_table_name)>0;
162}
163
164bool tkdatabase::has_view(const tkstring &_table_name)
165{
166 return std::count(fViews.begin(), fViews.end(), _table_name)>0;
167}
168
170{
171 fTables.insert(std::make_pair(_table_name,tkdb_table(_table_name.data(),fDataBase)));
172 return fTables[_table_name];
173}
174
176{
177 tkstring sql = tkstring::form("DROP TABLE %s ", _table_name.data());
178 exec_sql(sql.data());
179 fTables.erase(_table_name.data());
180}
181
183{
184 return &fTables[_table_name.data()];
185}
186
187void tkdatabase::print(const tkstring &_properties, const tkstring &_opt)
188{
189 for(auto &table : fTables){
190 for(auto &col : table.second.get_columns()) {
191 if(_properties.contains(col.first.data())||_properties.equal_to("*")) {
192 if(_opt.contains("notnull")&&!strcmp(col.second.get_value().data(),"")) continue;
193 glog << "|";
194 glog << col.first << "=" << col.second.get_value();
195 }
196 }
197 }
198 glog << do_endl;
199}
200
201void tkdatabase::begin(tkstring _selection, tkstring _from, tkstring _condition, tkstring _loop_name, tkstring _extra_cmd)
202{
203 glog.set_class("database");
204 glog.set_method(tkstring::Form("begin(%s,%s,%s,%s,%s)",_selection.data(),_from.data(),_condition.data(),_loop_name.data(),_extra_cmd.data()));
205
206 if(fSQLStatement.count(_loop_name)) {
207 glog << warning_v << "Previous sql statement not yet closed. Closing in to start new statement..." << do_endl;
208 end(_loop_name);
209 }
210
211 if(!_condition.empty()) _condition.prepend("where ");
212
213 sqlite3_stmt* sqlstm = nullptr;
214 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);
215 if( rc!=SQLITE_OK ) {
216 glog << error_v << "SQL error: " << sqlite3_errmsg(fDataBase) << do_endl;
217 glog << tkstring::form("select %s from %s %s",_selection.data(),_from.data(),_condition.data()) << do_endl;
218 if(sqlstm) sqlite3_finalize(sqlstm);
219 sqlite3_free(nullptr);
220 }
221 else {
222 fSQLStatement.emplace(_loop_name, sqlstm);
223 fReading = true;
224 }
225
226 glog.clear();
227}
228
229bool tkdatabase::next(const tkstring &_loop_name)
230{
231 glog.set_class("database");
232 glog.set_method("next()");
233
234 if(!fSQLStatement.count(_loop_name)) {
235 glog << error_v << "No sql statement name "<< _loop_name << " prepared, please call begin() to prepare it " << do_endl;
236 glog.clear();
237 return false;
238 }
239
240 int ret_code = sqlite3_step(fSQLStatement[_loop_name]);
241 if(ret_code == SQLITE_ROW) {
242 int cols = sqlite3_column_count(fSQLStatement[_loop_name]);
243 for (int i=0; i<cols; i++) {
244 const unsigned char* tmp = sqlite3_column_text(fSQLStatement[_loop_name], i);
245 const char* col_name = sqlite3_column_name(fSQLStatement[_loop_name], i);
246 for(auto &table : fTables){
247 if(table.second.has_column(col_name)) {
248 if(tmp == nullptr)
249 table.second[col_name].set_value_str("");
250 else
251 table.second[col_name].set_value_str(reinterpret_cast<const char*>(tmp));
252 break;
253 }
254 }
255 }
256 glog.clear();
257 return true;
258 }
259 end(_loop_name);
260 glog.clear();
261 return false;
262}
263
264void tkdatabase::end(const tkstring &_loop_name)
265{
266 glog.set_class("database");
267 glog.set_method("end()");
268 if(!fSQLStatement.count(_loop_name)) {
269 glog << error_v << "No sql statement prepared to close..." << do_endl;
270 glog.clear();
271 return;
272 }
273 sqlite3_finalize(fSQLStatement[_loop_name]);
274 fReading = false;
275 fSQLStatement.erase(_loop_name);
276 for(auto &table : fTables) table.second.reset_column_values();
277 glog.clear();
278}
279
280int tkdatabase::count(const tkstring &_from, const tkstring &_condition)
281{
282 int counts = 0;
283 begin("*",_from,_condition,"count");
284 while(next("count")) counts++;
285 return counts;
286}
287
289{
290 glog.set_class("database");
291 glog.set_method(tkstring::Form("get_value(%s,%s,%s)",_selection.data(),_from.data(),_condition.data()));
292
293 if(_selection.contains(",")) glog << error_v << "Selection should contains only one column name !" << do_endl;
294 _condition += " LIMIT 1";
295
296 begin(_selection,_from,_condition,"get_value");
297 if(next("get_value")) {
298 tkstring val = "";
299 for(auto &table : fTables) if(table.second.has_column(_selection)) val = table.second[_selection.data()].get_value();
300 if(next("get_value")) glog << warning_v << "More than one entry corresponding to this criteria : only first value returned" << do_endl;
301 if(fSQLStatement.count("get_value")) end("get_value");
302 glog.clear();
303 return val;
304 }
305
306 glog << error_v << "No entry corresponding to the asked criteria" << do_endl;
307 glog.clear();
308 return "";
309}
310
311int tkdatabase::exec_sql(const char *_cmd)
312{
313 char *zErrMsg = nullptr;
314 int rc = sqlite3_exec(fDataBase, _cmd, nullptr, nullptr, &zErrMsg);
315
316 if( rc != SQLITE_OK ) {
317 glog << error << "SQL error: " << zErrMsg << " while excuting command: " << _cmd << do_endl;
318 sqlite3_free(zErrMsg);
319 }
320 else {}
321 return rc;
322}
323
324#ifdef HAS_ROOT
326ClassImp(tkdatabase);
327#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:31
static const char * form(const char *_format,...)
Definition tkstring.cpp:408
std::vector< tkstring > tokenize(const tkstring &_delim=" ") const
Create a vector of string separated by at least one delimiter.
Definition tkstring.cpp:231
static tkstring Form(const char *_format,...)
Definition tkstring.cpp:322
bool ends_with(const char *_s, ECaseCompare _cmp=kExact) const
Definition tkstring.cpp:218
bool equal_to(const char *_s, ECaseCompare _cmp=kExact) const
Returns true if the string and _s are identical.
Definition tkstring.cpp:211
bool contains(const char *_pat, ECaseCompare _cmp=kExact) const
Definition tkstring.h:174
tkstring & prepend(const tkstring &_st)
Definition tkstring.h:201
tkstring & append(const tkstring &_st)
Definition tkstring.h:204
tkstring & to_upper()
Change all letters to upper case.
Definition tkstring.cpp:42
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