14#include "tkdatabase.h"
38 if(g_database)
return g_database;
40 std::lock_guard<std::recursive_mutex> lock(get_mutex());
42 if ( g_database ==
nullptr ) {
51 std::lock_guard<std::recursive_mutex> lock(get_mutex());
53 if(g_database ==
nullptr && opening_db)
open(
tkstring::Form(
"%s/databases/TkN.db",TKN_SYS));
58 std::lock_guard<std::recursive_mutex> lock(get_mutex());
59 if(g_database ==
this) g_database =
nullptr;
64 glog.set_class(
"database");
65 glog.set_method(
tkstring::Form(
"open(%s,%s)",_db_name.data(),_option.data()));
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;
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);
84 fMode = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
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;
92 fMode = SQLITE_OPEN_READONLY;
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;
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();
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 ");
124 sqlite3_close(fDataBase);
129 const char *sql =
"SELECT name FROM sqlite_master WHERE type='table'";
131 sqlite3_prepare_v2(fDataBase, sql, -1, &stmt,
nullptr);
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();
138 sqlite3_finalize(stmt);
143 const char *sql =
"SELECT name FROM sqlite_master WHERE type='view'";
145 sqlite3_prepare_v2(fDataBase, sql, -1, &stmt,
nullptr);
147 while(sqlite3_step(stmt) == SQLITE_ROW) {
148 tkstring table_name(sqlite3_column_text(stmt, 0));
149 fViews.push_back(table_name);
151 sqlite3_finalize(stmt);
156 fTables.insert(std::make_pair(_table.
get_name(),_table));
161 return fTables.count(_table_name)>0;
166 return std::count(fViews.begin(), fViews.end(), _table_name)>0;
171 fTables.insert(std::make_pair(_table_name,
tkdb_table(_table_name.data(),fDataBase)));
172 return fTables[_table_name];
179 fTables.erase(_table_name.data());
184 return &fTables[_table_name.data()];
189 for(
auto &table : fTables){
190 for(
auto &col : table.second.get_columns()) {
192 if(_opt.
contains(
"notnull")&&!strcmp(col.second.get_value().data(),
""))
continue;
194 glog << col.first <<
"=" << col.second.get_value();
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()));
206 if(fSQLStatement.count(_loop_name)) {
207 glog <<
warning_v <<
"Previous sql statement not yet closed. Closing in to start new statement..." <<
do_endl;
211 if(!_condition.empty()) _condition.
prepend(
"where ");
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);
222 fSQLStatement.emplace(_loop_name, sqlstm);
231 glog.set_class(
"database");
232 glog.set_method(
"next()");
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;
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)) {
249 table.second[col_name].set_value_str(
"");
251 table.second[col_name].set_value_str(
reinterpret_cast<const char*
>(tmp));
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;
273 sqlite3_finalize(fSQLStatement[_loop_name]);
275 fSQLStatement.erase(_loop_name);
276 for(
auto &table : fTables) table.second.reset_column_values();
283 begin(
"*",_from,_condition,
"count");
284 while(
next(
"count")) counts++;
290 glog.set_class(
"database");
291 glog.set_method(
tkstring::Form(
"get_value(%s,%s,%s)",_selection.data(),_from.data(),_condition.data()));
293 if(_selection.
contains(
",")) glog <<
error_v <<
"Selection should contains only one column name !" <<
do_endl;
294 _condition +=
" LIMIT 1";
296 begin(_selection,_from,_condition,
"get_value");
297 if(
next(
"get_value")) {
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");
306 glog <<
error_v <<
"No entry corresponding to the asked criteria" <<
do_endl;
313 char *zErrMsg =
nullptr;
314 int rc = sqlite3_exec(fDataBase, _cmd,
nullptr,
nullptr, &zErrMsg);
316 if( rc != SQLITE_OK ) {
317 glog <<
error <<
"SQL error: " << zErrMsg <<
" while excuting command: " << _cmd <<
do_endl;
318 sqlite3_free(zErrMsg);
Interface to the sqlite database.
int count(const tkstring &_from, const tkstring &_condition="")
resets column values and ends the select statement
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.
std::string with usefull tricks from TString (ROOT) and KVString (KaliVeda) and more....
static const char * form(const char *_format,...)
std::vector< tkstring > tokenize(const tkstring &_delim=" ") const
Create a vector of string separated by at least one delimiter.
static tkstring Form(const char *_format,...)
bool ends_with(const char *_s, ECaseCompare _cmp=kExact) const
bool equal_to(const char *_s, ECaseCompare _cmp=kExact) const
Returns true if the string and _s are identical.
bool contains(const char *_pat, ECaseCompare _cmp=kExact) const
tkstring & prepend(const tkstring &_st)
tkstring & append(const tkstring &_st)
tkstring & to_upper()
Change all letters to upper case.
tklog & error_v(tklog &log)
tklog & warning_v(tklog &log)
tklog & error(tklog &log)
tklog & do_endl(tklog &log)
tklog & warning(tklog &log)