TkN 2.7
Toolkit for Nuclei
Loading...
Searching...
No Matches
tkdb_table.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 "tkdb_table.h"
15#include "tklog.h"
16
17namespace tkn {
25}
26
27using namespace tkn;
28
29tkdb_table::tkdb_table(const char *_name, sqlite3 *_db) :
30 fName(_name),
31 fDataBase(_db)
32{
33 glog.set_class("db_table");
34 // load();
35}
36
38 fName(_other.fName),
39 fDataBase(_other.fDataBase),
40 fColumns(_other.fColumns),
41 fOrderedColumnNames(_other.fOrderedColumnNames),
42 fConstraint(_other.fConstraint)
43{
44}
45
47{
48 if (this == &_other) return *this;
49 finalize_statements();
50 fName = _other.fName;
51 fDataBase = _other.fDataBase;
52 fColumns = _other.fColumns;
53 fOrderedColumnNames = _other.fOrderedColumnNames;
54 fConstraint = _other.fConstraint;
55 return *this;
56}
57
59 fName(std::move(_other.fName)),
60 fDataBase(_other.fDataBase),
61 fColumns(std::move(_other.fColumns)),
62 fOrderedColumnNames(std::move(_other.fOrderedColumnNames)),
63 fSQL_stmt(_other.fSQL_stmt),
64 fInsertStatement(_other.fInsertStatement),
65 fReading(_other.fReading),
66 fConstraint(std::move(_other.fConstraint))
67{
68 _other.fSQL_stmt = nullptr;
69 _other.fInsertStatement = nullptr;
70 _other.fReading = false;
71}
72
74{
75 if (this == &_other) return *this;
76 finalize_statements();
77 fName = std::move(_other.fName);
78 fDataBase = _other.fDataBase;
79 fColumns = std::move(_other.fColumns);
80 fOrderedColumnNames = std::move(_other.fOrderedColumnNames);
81 fSQL_stmt = _other.fSQL_stmt;
82 fInsertStatement = _other.fInsertStatement;
83 fReading = _other.fReading;
84 fConstraint = std::move(_other.fConstraint);
85 _other.fSQL_stmt = nullptr;
86 _other.fInsertStatement = nullptr;
87 _other.fReading = false;
88 return *this;
89}
90
92{
93 finalize_statements();
94}
95
96void tkdb_table::finalize_statements()
97{
98 if (fSQL_stmt) sqlite3_finalize(fSQL_stmt);
99 if (fInsertStatement) sqlite3_finalize(fInsertStatement);
100 fSQL_stmt = nullptr;
101 fInsertStatement = nullptr;
102 fReading = false;
103}
104
106{
107 glog.set_method(tkstring::Form("get_column_list(%s)",fName.data()));
108
109 sqlite3_stmt* stmt;
110 int rc = sqlite3_prepare_v2(fDataBase, tkstring::form("PRAGMA table_info('%s');",fName.data()), -1, &stmt, nullptr);
111 if( rc!=SQLITE_OK ){
112 glog << error_v << "SQL error: " << sqlite3_errmsg(fDataBase) << " while loading table '" << fName.data() << "'" << do_endl;
113 sqlite3_free(nullptr);
114 }
115
116 while((sqlite3_step(stmt)) == SQLITE_ROW) {
117 tkstring name = sqlite3_column_text(stmt, 1);
118 tkstring type = sqlite3_column_text(stmt, 2);
119 add_column(name.data(),type.data());
120 }
121
122 sqlite3_finalize(stmt);
123}
124
126{
127 glog << info << blue << tkstring::form("Table '%s'",fName.data()) << do_endl;
128 print_columns(_opt);
129}
130
132{
133// glog.set_method(tkstring::Form("print_columns(%s)",fName.data()));
134
135 if(_opt.contains("verbose")) glog << info << yellow << tkstring::form("[%3d] columns in '%s' table",fColumns.size(),fName.data()) << do_endl;
136 int ii = 0;
137 for(auto &column : fColumns) {
138 if(_opt.contains("notnull")&&column.second.is_empty()) continue;
139 if(column.first.contains(_opt)) glog << info << tkstring::form("[%3d] %20s %6s %s",ii++,column.second.get_name(),column.second.get_type(),column.second.get_value().data()) << do_endl;
140 }
141}
142
143void tkdb_table::print_rows(const char *_selection, const char* _properties)
144{
145 tkstring sel = _selection;
146 tkstring pro = _properties;
147
148 std::vector<tkstring> colnames;
149
150 if(pro.equal_to("*")) colnames = fOrderedColumnNames;
151 else colnames= pro.tokenize(",");
152
153 for(auto col : colnames) glog << tkstring::form("%20s",fColumns[col.data()].get_name());
154 glog << do_endl;
155
156 begin(sel,_properties);
157 while(next())
158 {
159 for(auto col : colnames) glog << tkstring::form("%20s",fColumns[col.data()].get_value().data());
160 glog << do_endl;
161 }
162}
163
164void tkdb_table::begin(tkstring _condition, tkstring _selection)
165{
166 if(fReading)
167 {
168 glog << warning << "Previous sql statement not yet closed. Closing in to start new statement..." << do_endl;
169 end();
170 }
171
172 tkstring cmd = tkstring::form("select %s from %s where %s",_selection.data(),fName.data(),_condition.data());
173
174 int rc = sqlite3_prepare_v2(fDataBase, cmd.data(), -1, &fSQL_stmt, nullptr);
175 if( rc!=SQLITE_OK ){
176 glog << error << "SQL error: " << sqlite3_errmsg(fDataBase) << "while executing cmd : " << cmd.data() << do_endl;
178 sqlite3_free(nullptr);
179 }
180 else fReading = true;
181}
182
184{
185 if(!fReading) {
186 glog << error << "No sql statement prepared, please call begin() to prepare it " << do_endl;
187 return false;
188 }
189
190 int ret_code = sqlite3_step(fSQL_stmt);
191 if(ret_code== SQLITE_ROW) {
192 int cols = sqlite3_column_count(fSQL_stmt);
193 for (int i=0; i<cols; i++) {
194 const unsigned char* tmp = sqlite3_column_text(fSQL_stmt, i);
195 if(tmp == nullptr)
196 fColumns[sqlite3_column_name(fSQL_stmt, i)].set_value("");
197 else
198 fColumns[sqlite3_column_name(fSQL_stmt, i)].set_value(sqlite3_column_text(fSQL_stmt, i));
199 }
200 return true;
201 }
202 end();
203 return false;
204}
205
207{
208 if(!fReading) {glog << error << "No sql statement prepared to close..." << do_endl; return;}
209 sqlite3_finalize(fSQL_stmt);
210 fSQL_stmt = nullptr;
211 fReading = false;
213}
214
215//tkstring db_table::get_value(const char *_property, const char *_selection)
216//{
217// tkstring sel = _selection;
218// glog.set_class("db_table");
219// glog.set_method(tkstring::Form("get_value('%s',%s)",_property,sel.data()));
220
221// sqlite3_stmt* stmt;
222// int rc = sqlite3_prepare_v2(fDataBase, tkstring::form("select %s from %s where %s",_property,fName.data(),sel.data()), -1, &stmt, 0);
223// if( rc!=SQLITE_OK ){
224// glog << error_v << "SQL error: " << sqlite3_errmsg(fDataBase) << do_endl;
225// print_columns();
226// sqlite3_free(0);
227// }
228
229// tkstring value = "";
230// int ret_code = 0;
231// while((ret_code = sqlite3_step(stmt)) == SQLITE_ROW) {
232// value = reinterpret_cast< const char* >(sqlite3_column_text(stmt, 0));
233// break;
234// }
235// sqlite3_finalize(stmt);
236// return value;
237//}
238
239void tkdb_table::add_column(const char *_colname, const char *_coltype)
240{
241 tkdb_column col(_colname,_coltype);
242 tkstring col_name(_colname);
243 fColumns.insert(std::make_pair(col_name,col));
244 fOrderedColumnNames.push_back(col_name);
245}
246
247void tkdb_table::add_constraint(const char *_constraint)
248{
249 fConstraint += _constraint;
250 fConstraint += " ";
251}
252
253bool tkdb_table::has_column(const tkstring &_col_name)
254{
255 return fColumns.count(_col_name)>0;
256}
257
259{
260 const auto column = fColumns.find(_col_name);
261 return column == fColumns.end() ? nullptr : &column->second;
262}
263
265{
266 for (auto &column : fColumns)
267 column.second.set_value_str("");
268}
269
271{
272 if (!fInsertStatement && !prepare_insert_statement()) {
274 return;
275 }
276
277 int parameter = 1;
278 bool bindings_ok = true;
279 for (const auto &name : fOrderedColumnNames) {
280 auto &column = fColumns[name];
281 int rc = SQLITE_OK;
282 if (column.is_empty())
283 rc = sqlite3_bind_null(fInsertStatement, parameter);
284 else {
285 const tkstring value = column.get_value();
286 rc = sqlite3_bind_text(fInsertStatement, parameter, value.data(), -1, SQLITE_TRANSIENT);
287 }
288 if (rc != SQLITE_OK) {
289 glog << error << "SQL bind error while inserting into " << fName << ": "
290 << sqlite3_errmsg(fDataBase) << do_endl;
291 bindings_ok = false;
292 break;
293 }
294 ++parameter;
295 }
296
297 if (bindings_ok) {
298 const int rc = sqlite3_step(fInsertStatement);
299 if (rc != SQLITE_DONE) {
300 glog << error << "SQL insert error in " << fName << ": "
301 << sqlite3_errmsg(fDataBase) << do_endl;
302 }
303 }
304 sqlite3_reset(fInsertStatement);
305 sqlite3_clear_bindings(fInsertStatement);
307}
308
309bool tkdb_table::prepare_insert_statement()
310{
311 if (fOrderedColumnNames.empty()) return false;
312
313 tkstring sql = tkstring::form("INSERT INTO %s (", fName.data());
314 tkstring parameters = "VALUES (";
315 for (const auto &name : fOrderedColumnNames) {
316 sql += name;
317 sql += ",";
318 parameters += "?,";
319 }
320 sql.erase(sql.length() - 1);
321 parameters.erase(parameters.length() - 1);
322 sql += ") ";
323 parameters += ")";
324 sql += parameters;
325
326 const int rc = sqlite3_prepare_v2(fDataBase, sql.data(), -1, &fInsertStatement, nullptr);
327 if (rc != SQLITE_OK) {
328 glog << error << "SQL prepare error for " << fName << ": "
329 << sqlite3_errmsg(fDataBase) << do_endl;
330 fInsertStatement = nullptr;
331 return false;
332 }
333 return true;
334}
335
337{
338// UPDATE the table. _where should contain a statment returning one column
339// like isotope_id = 27 (to be tested...)
340
341 tkstring sql = tkstring::form("UPDATE %s SET ", fName.data());
342 for(auto &column : fColumns) {
343 if(column.second.is_empty()) continue;
344 sql += column.second.get_name();
345 sql += " = ";
346 if(column.second.is_text()) sql +="'";
347 sql += column.second.get_value();
348 if(column.second.is_text()) sql +="'";
349 sql +=",";
350 }
351 sql.erase(sql.length()-1);
352 sql += " WHERE ";
353 sql += _where.data();
354 sql += ";";
355 exec_sql(sql.data());
357}
358
360{
361 tkstring sql = tkstring::form("CREATE TABLE %s (", fName.data());
362
363 for (auto it: fOrderedColumnNames) {
364 sql += fColumns[it.data()].get_name();
365 sql += " ";
366 sql += fColumns[it.data()].get_type();
367 sql +=",";
368 }
369 sql = sql.substr(0,sql.size()-1);
370 if(!fConstraint.empty()) {
371 sql += ", ";
372 sql += fConstraint.data();
373 }
374 sql +=");";
375 exec_sql(sql.data());
376}
377
379{
380 for (auto &column : fColumns)
381 column.second.set_value_str("0");
382 push_row();
383}
384
385int tkdb_table::exec_sql(const char *_cmd)
386{
387 char *zErrMsg = nullptr;
388 int rc = sqlite3_exec(fDataBase, _cmd, nullptr, nullptr, &zErrMsg);
389
390 if( rc != SQLITE_OK ) {
391 glog << error << "SQL error: " << zErrMsg << " while excuting command: " << _cmd << do_endl;
392 sqlite3_free(zErrMsg);
393 }
394 else {}
395 return rc;
396}
397
398void tkdb_table::read_measure(measure_data_struct &_struct, const tkstring &_col_base_name)
399{
400 _struct.clear();
401 const auto columns = get_measure_columns(_col_base_name);
402 if(!columns[0]) {
403 glog << warning << "no column named: " << _col_base_name << " in database: " << fName << do_endl;
404 return;
405 }
406 read_measure(_struct, columns);
407}
408
410{
411 static const std::array<const char *, 6> suffixes = {
412 "", "_unit", "_unc", "_unc_low", "_unc_high", "_info"
413 };
414 measure_columns columns{};
415 for (std::size_t index = 0; index < suffixes.size(); ++index) {
416 tkstring name = _col_base_name;
417 name += suffixes[index];
418 columns[index] = get_column(name);
419 }
420 return columns;
421}
422
424{
425 // A caller may reuse the same structure for several columns. Always
426 // reset it first so that an SQL NULL cannot leave the previous measure's
427 // value, unit, or uncertainty behind.
428 _struct.clear();
429
430 if (!_columns[0] || _columns[0]->is_empty()) return;
431
432 _struct.value = _columns[0]->get_value().atof();
433
434 if(_columns[1] && !_columns[1]->is_empty()) _struct.unit = _columns[1]->get_value();
435 if(_columns[2] && !_columns[2]->is_empty()) _struct.err = _columns[2]->get_value().atof();
436 if(_columns[3] && !_columns[3]->is_empty()) _struct.err_low = _columns[3]->get_value().atof();
437 if(_columns[4] && !_columns[4]->is_empty()) _struct.err_high = _columns[4]->get_value().atof();
438 if(_columns[5] && !_columns[5]->is_empty()) _struct.info = _columns[5]->get_value();
439
440 _struct.filled = true;
441}
442
443
444#ifdef HAS_ROOT
446ClassImp(tkdb_table)
447#endif
Simple structure to store a table column.
Definition tkdb_column.h:26
void set_value_str(const char *val)
Definition tkdb_column.h:51
Representaiton of a sqlite data table.
Definition tkdb_table.h:31
std::array< tkdb_column *, 6 > measure_columns
Definition tkdb_table.h:81
void read_measure(measure_data_struct &_struct, const tkstring &_col_base_name)
tkdb_column * get_column(const tkstring &_col_name)
measure_columns get_measure_columns(const tkstring &_col_base_name)
void begin(tkstring _condition, tkstring _selection="*")
bool has_column(const tkstring &_col_name)
void update_row(const tkstring &_where)
tkdb_table & operator=(const tkdb_table &_other)
void load()
resets column values and ends the select statement
bool next()
executes the select statement
void print_columns(const tkstring &_opt="")
void add_constraint(const char *_constraint)
void write_to_database()
void print_rows(const char *_selection, const char *_properties="*")
void end()
reads the next entry coresponding to the select statement and fills columns
void print(const tkstring &_opt="")
void add_column(const char *_colname, const char *_coltype)
void reset_column_values()
virtual ~tkdb_table()
tkdb_table(const char *_name, sqlite3 *_db)
std::string with usefull tricks from TString (ROOT) and KVString (KaliVeda) and more....
Definition tkstring.h:33
static const char * form(const char *_format,...)
Definition tkstring.cpp:438
std::vector< tkstring > tokenize(const tkstring &_delim=" ") const
Create a vector of string separated by at least one delimiter.
Definition tkstring.cpp:292
static tkstring Form(const char *_format,...)
Definition tkstring.cpp:368
tkstring substr(size_type __pos=0, size_type __n=npos) const
Inlines.
Definition tkstring.h:160
bool equal_to(const char *_s, ECaseCompare _cmp=kExact) const
Returns true if the string and _s are identical.
Definition tkstring.cpp:259
bool contains(const char *_pat, ECaseCompare _cmp=kExact) const
Definition tkstring.h:184
Definition tklog.cpp:16
tklog & yellow(tklog &log)
Definition tklog.h:244
tklog & error_v(tklog &log)
Definition tklog.h:407
tklog & info(tklog &log)
Definition tklog.h:313
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
tklog & blue(tklog &log)
Definition tklog.h:247
data structure used to fill a tkmeasure object from the sqlite database
Definition tkdb_table.h:51