KaliVeda
Toolkit for HIC analysis
Loading...
Searching...
No Matches
SQLiteDB.cpp
1//Created by KVClassFactory on Mon Jul 25 15:33:56 2016
2//Author: John Frankland,,,
3
4#include "SQLiteDB.h"
5#include <TList.h>
6#include "TSQLResult.h"
7#include "TSQLRow.h"
8#include "TSQLTableInfo.h"
9#include "TSQLColumnInfo.h"
10#include <KVString.h>
11#include <iostream>
12#include "KVError.h"
13#include <iomanip>
14#include "TSystem.h"
15
19
20
21namespace KVSQLite {
22
23 // static maps instantiation
24 std::map<TString, KVSQLite::column_type::types> table::type_map;
25 std::map<KVSQLite::column_type::types, TString> column::inv_type_map;
26
27
33
34 std::unique_ptr<TSQLResult> database::SelectRowsFromTable(const TString& table, const TString& columns, const TString& condition) const
35 {
36 // \param[in] table name of table
37 // \param[in] columns comma-separated list of columns
38 // \param[in] condition selection to be applied, if any
39 // \returns result of query `SELECT [columns] FROM [table] WHERE [condition]`
40
41 TString query;
42 query.Form("SELECT %s FROM '%s'", columns.Data(), table.Data());
43 if (condition != "") query += Form(" WHERE %s", condition.Data());
44 return std::unique_ptr<TSQLResult>(fDBserv->Query(query));
45 }
46
47
48
51
53 {
54 // initialise map of database tables from existing database
55 std::unique_ptr<TList> tl(fDBserv->GetTablesList());
56 TObject* o;
57 TIter it_tab(tl.get());
58 while ((o = it_tab())) {
59
60 table t(o->GetName());
61
62 std::unique_ptr<TSQLResult> columnRes(fDBserv->GetColumns("", o->GetName()));
63 if (!columnRes.get()) {
64 Error("read_table_infos", "Cannot get information on columns for table %s", o->GetName());
65 return;
66 }
67 std::unique_ptr<TSQLRow> columnRow(columnRes->Next());
68 while ((columnRow.get()) != nullptr) {
69 column& col = t.add_column(columnRow->GetField(1), columnRow->GetField(2));
70 TString primary_key(columnRow->GetField(5));
71 if (primary_key.Atoi() == 1) col.set_constraint("PRIMARY KEY");
72 columnRow.reset(columnRes->Next());
73 }
74 fTables.insert(std::pair<std::string, KVSQLite::table>(o->GetName(), t));
75 }
76
77 }
78
79
80
83
85 {
86 // print list of tables
87 std::cout << "Tables in database:" << std::endl;
88#ifdef WITH_CPP11
89 for (auto it = fTables.begin();
90#else
91 for (std::map<std::string, KVSQLite::table>::const_iterator it = fTables.begin();
92#endif
93 it != fTables.end(); ++it) {
94 std::cout << "\t" << it->first << std::endl;
95 }
96 }
97
98
99
109
110 void database::open(const TString& dbfile)
111 {
112 // Open/create sqlite db file given path
113 //
114 // Any special characters/environment variables are first expanded, so
115 // you can use:
116 //~~~~
117 // ~/mydata.db
118 // $(SOME_PATH)/toto.db
119 //~~~~
120
121 TString exp_path = dbfile;
122 if (gSystem->ExpandPathName(exp_path)) {
123 Error("open", "problem with SQLite database filename: %s", dbfile.Data());
124 fIsValid = false;
125 return;
126 }
127 TString uri = "sqlite://" + exp_path;
128 fDBserv.reset(static_cast<TSQLiteServer*>(TSQLServer::Connect(uri, 0, 0)));
129 // check for valid database file
130 if (!fDBserv->Exec("pragma schema_version")) {
131 fDBserv->Close();
132 fIsValid = false;
133 return;
134 }
135 fIsValid = true;
137 }
138
139
140
142
143 void database::PrintResults(TSQLResult* tabent, int column_width) const
144 {
145 int nfields = tabent->GetFieldCount();
146 std::unique_ptr<TSQLRow> row(nullptr);
147 for (int r = -1; true; ++r) {
148 if (r > -1) {
149 row.reset(tabent->Next());
150 if (row.get() == nullptr) break;
151 std::cout << std::setw(6) << r;
152 }
153 for (int f = 0; f < nfields; ++f) {
154 if (r < 0) {
155 if (f == 0) std::cout << std::setw(6) << "#";
156 std::cout << "|" << std::setw(column_width) << tabent->GetFieldName(f) ;
157 }
158 else {
159 std::cout << "|" << std::setw(column_width) << row->GetField(f) ;
160 }
161 }
162 std::cout << "\n";
163 }
164 }
165
166
167
170
171 void database::Dump() const
172 {
173 // Print on stdout contents of database
174
175 std::cout << "Database : " << fDBserv->GetDB() << " [" << fDBserv->GetDBMS() << "]\n";
176 std::unique_ptr<TList> tl(fDBserv->GetTablesList());
177 TObject* o;
178 TIter it_tab(tl.get());
179 while ((o = it_tab())) {
180 std::cout << "\t";
181 std::cout << "Table : " << o->GetName() << "\n";
182 std::unique_ptr<TSQLResult> tabent = SelectRowsFromTable(o->GetName());
183 PrintResults(tabent.get());
184 }
185 std::cout << std::endl;
186 }
187
188
191
192 void database::print_selection(const TString& table, const TString& columns, const TString& condition, int column_width) const
193 {
194 // Print on stdout contents of database
195
196 std::unique_ptr<TSQLResult> tabent = SelectRowsFromTable(table, columns, condition);
197 PrintResults(tabent.get(), column_width);
198 std::cout << std::endl;
199 }
200
201
202
218
220 {
221 // add table to database (if it does not exist already)
222 //
223 // _WARNING:_ after calling this method, do not use the table given as argument
224 //
225 // it does not correspond to the table in the database
226 //
227 // instead use `db["table name"]` to access the table
228 //
229 //~~~~{.cpp}
230 // e.g. KVSQLite::table tt("some table");
231 // tt.add_column(...);
232 // db.add_table(tt);
233 // db["some table"]["column"].set_data(...);
234 //~~~~
235
236 TString command("CREATE ");
237 if (t.is_temporary()) command += "TEMPORARY ";
238 command += "TABLE IF NOT EXISTS \"";
239 command += t.name();
240 command += "\"";
241 command += " (";
242 for (int i = 0; i < t.number_of_columns(); ++i) {
243 if (i) command += ", ";
244 command += t[i].get_declaration();
245 }
246 command += ")";
247 //std::cout << command << std::endl;
248 if (fDBserv->Exec(command))
249 fTables.insert(std::pair<std::string, KVSQLite::table>(t.name(), t));
250 }
251
252
253
268
270 {
271 // Call this method before insert_dat_row() in order to perform bulk data
272 // insertion operation. i.e. something like:
273 //
274 //~~~~{.cpp}
275 // db.prepare_data_insertion("my_table");
276 // while(...){ // loop over data to insert
277 // // set up data in table
278 // db.insert_data_row();
279 // }
280 // db.end_data_insertion(); // terminate data insertion
281 //~~~~
282 // Until method end_data_insertion() is called, you cannot call prepare_data_insertion()
283 // with a different table name.
284
285 if (fInserting) {
286 if (fBulkTable) {
287 Error("database::prepare_data_insertion",
288 "bulk insertion in progress for table %s; call database::commit() to terminate transaction",
289 fBulkTable->name());
290 return false;
291 }
292 else {
293 Error("database::prepare_data_insertion",
294 "bulk insertion in progress; call database::commit() to terminate transaction");
295 return false;
296 }
297 }
298 if (fSelecting) {
299 Error("database::prepare_data_insertion",
300 "data retrieval in progress; call get_next_result() until it returns false");
301 return false;
302 }
303 fInserting = true;
304 fDBserv->StartTransaction();
305 // set up SQL statement for data insertion into table
306 fBulkTable = &fTables[table.Data()];
308 int ncol = fBulkTable->number_of_columns();
309 int idx = 0;
310 for (int i = 0; i < ncol; ++i) {
311 if (idx) com += ",";
312 if (!(*fBulkTable)[i].primary_key()) {
313 com += Form("\"%s\"", (*fBulkTable)[i].name());;
314 ++idx;
315 }
316 }
317 com += ") VALUES (";
318 idx = 0;
319 for (int i = 0; i < ncol; ++i) {
320 if (idx) com += ",";
321 if (!(*fBulkTable)[i].primary_key()) {
322 com += "?";
323 ++idx;
324 }
325 }
326 com += ")";
327 //std::cout << com << std::endl;
328 fSQLstmt.reset(fDBserv->Statement(com));
329 return true;
330 }
331
332
333
335
336 const char* table::get_insert_command() const
337 {
338 switch (fInsert) {
340 return Form("INSERT OR FAIL INTO \"%s\"(", name());
341 break;
343 return Form("INSERT OR IGNORE INTO \"%s\"(", name());
344 break;
346 return Form("INSERT OR REPLACE INTO \"%s\"(", name());
347 break;
348 default:
350 break;
351 }
352 return Form("INSERT INTO \"%s\"(", name());
353 }
354
355
356
359
360 const char* column::get_declaration() const
361 {
362 // return declaration for column, including type & constraint
363
364 static TString decl;
365 decl.Form("\"%s\" %s", name(), type_name());
366 if (fForeignKey) {
367 decl += ", FOREIGN KEY";
368 decl += Form("(\"%s\")", name());
369 decl += " REFERENCES ";
370 decl += Form("\"%s\"(\"%s\")", fFKtable.Data(), fFKcolumn.Data());
371 }
372 else {
373 decl += " ";
374 decl += fConstraint;
375 }
376 return decl.Data();
377 }
378
379
380
392
394 {
395 // Call (repeatedly) after a call to prepare_data_insertion()
396 // in order to insert current contents of table columns as a new row in the database.
397 //
398 // Value of each column should first be set like this:
399 //
400 //~~~~{.cpp}
401 // db["table"]["id"].set_data(6);
402 // db["table"]["name"].set_data("triumph");
403 //~~~~
404 // Call end_data_insertion() when all data has been inserted
405
406 if (!fInserting || !fBulkTable) {
407 Error("database::insert_data_row",
408 "no transaction initialized; call prepare_data_insertion(name_table) before this method");
409 return;
410 }
411 if (fSelecting) {
412 Error("database::insert_data_row",
413 "data retrieval in progress; call get_next_result() until it returns false, then call prepare_data_insertion(name_table) before this method");
414 return;
415 }
416 int ncol = fBulkTable->number_of_columns();
417 fSQLstmt->NextIteration();
418 int idx = 0;
419 for (int i = 0; i < ncol; ++i) {
420 if (!(*fBulkTable)[i].primary_key()) {
421 (*fBulkTable)[i].set_data_in_statement(fSQLstmt.get(), idx);
422 ++idx;
423 }
424 }
425 }
426
427
428
432
434 {
435 // Call after prepare_data_insertion() & insert_data_row() have been
436 // used to insert data into a table
437
438 if (!fInserting) {
439 Error("database::end_data_insertion",
440 "no transaction initialized; call prepare_data_insertion(name_table) first");
441 return;
442 }
443 if (fSelecting) {
444 Error("database::insert_data_row",
445 "data retrieval in progress; call get_next_result() until it returns false, then call prepare_data_insertion(name_table) before this method");
446 return;
447 }
448 fBulkTable = nullptr;
449 fSQLstmt->Process();
450 fDBserv->Commit();
451 fInserting = false;
452 }
453
454
457
458 void database::print_selected_data(const TString& tables, const TString& columns, const TString& selection, bool distinct, const TString& anything_else)
459 {
460 // Print out results of a call to select_data().
461
462 if (select_data(tables, columns, selection, distinct, anything_else)) {
463 for (auto col : fSQLstmtCols) {
464 std::cout << col->get_table() << "::" << col->name() << "\t\t\t";
465 }
466 std::cout << std::endl;
467 while (get_next_result()) {
468 for (auto col : fSQLstmtCols) {
469 std::cout << col->data().GetString() << "\t\t\t";
470 }
471 std::cout << std::endl;
472 }
473 }
474 }
475
476
492
493 bool database::select_data(const TString& tables, const TString& columns, const TString& selection, bool distinct, const TString& anything_else) const
494 {
495 // Select data in database from given table(s) according to
496 //~~~~
497 // SELECT [columns] FROM [tables] WHERE [selection] [anything_else]
498 //~~~~
499 // In order to retrieve results, call get_next_result() until it returns false.
500 //
501 // \param tables if more than 1 table is given, separate table names with commas.
502 // if 1 table has a foreign key referencing the other, this allows to JOIN data
503 // in both tables together. [columns] can then refer to columns in either table.
504 // \param columns ="*" by default, i.e. data from all columns is retrieved.
505 // If specific column data is to be selected, give a comma-separated list of
506 // column names. These will be quoted correctly in case they contain spaces.
507 // \param distinct can be used in conjunction with a selection of specific columns in order
508 // to retrieve only rows of data with different values for the column(s).
509 if (fInserting) {
510 Error("database::select_data",
511 "data insertion in progress; call end_data_insertion() before retrieving data");
512 return false;
513 }
514 if (fSelecting) {
515 Error("database::select_data",
516 "data retrieval already in progress; call get_next_result() until it returns false before making new selection");
517 return false;
518 }
519 fSQLstmtCols.clear();
520 std::list<const table*> table_list;
521 KVString table_selection(""), _tables(tables);
522 _tables.Begin(",");
523 // put quoted table names in table_selection
524 int i(0);
525 while (!_tables.End()) {
526 TString tabnam = _tables.Next();
527 table_list.push_back(& operator[](tabnam));
528 if (i) table_selection += " NATURAL JOIN ";
529 table_selection += Form("\"%s\"", tabnam.Data());
530 ++i;
531 }
532
533 KVString column_selection(""), _columns(columns);
534 if (columns == "*") {
535 column_selection = "*";
536 distinct = false; // don't allow 'SELECT DISTINCT * FROM ....' (?)
537 // find right column in right table for each item
538 // loop over all columns in each table
539 for (auto tabs : table_list) {
540 for (int i = 0; i < tabs->number_of_columns(); ++i) {
541 fSQLstmtCols.push_back(&(*tabs)[i]);
542 }
543 }
544 }
545 else {
546 if (distinct) column_selection = "DISTINCT ";
547 // put quoted column names in column_selection
548 _columns.Begin(",");
549 int i(0);
550 while (!_columns.End()) {
551 TString colnam = _columns.Next();
552 if (i) column_selection += ", ";
553 column_selection += Form("\"%s\"", colnam.Data());
554 ++i;
555 // find right column in right table for this item
556 for (auto tabs : table_list) if (tabs->has_column(colnam)) fSQLstmtCols.push_back(&(*tabs)[colnam]);
557 }
558 }
559
560 TString cond = Form("SELECT %s FROM %s", column_selection.Data(), table_selection.Data());
561 if (selection != "") cond += Form(" WHERE %s", selection.Data());
562 if (anything_else != "") cond += Form(" %s", anything_else.Data());
563 fSQLstmt.reset(fDBserv->Statement(cond));
564 if (fSQLstmt.get() == nullptr) {
565 Error("database::select_data", "problem processing : %s", cond.Data());
566 fSelecting = false;
567 fBulkTable = nullptr;
568 return false;
569 }
570 fSQLstmt->EnableErrorOutput();
571 if (fSQLstmt->Process()) {
572 fSQLstmt->StoreResult();
573 fSelecting = true;
574 fEmptyResultSet = false;
575 return true;
576 }
577 else if (!fSQLstmt->IsError()) {
578 // query ok, no results correspond to selection
579 fSQLstmt->StoreResult();
580 fSelecting = true;
581 fEmptyResultSet = true;
582 return true;
583 }
584 fSelecting = false;
585 fBulkTable = nullptr;
586 return false;
587 }
588
589
590
594
596 {
597 // Retrieve next result row resulting from previous call to select_data()
598 // \returns kFALSE when no more data is retrieved
599
600 if (fInserting) {
601 Error("database::get_next_result",
602 "data insertion in progress; call end_data_insertion() then select_data() before this method");
603 return false;
604 }
605 if (!fSelecting) {
606 Error("database::get_next_result",
607 "no data retrieval in progress; select_data() must be called and return true before calling this method");
608 return false;
609 }
610 if (!fEmptyResultSet && fSQLstmt->NextResultRow()) {
611 // set column data
612 int idx = 0;
613 for (auto col : fSQLstmtCols) {
614 col->set_data_from_statement(fSQLstmt.get(), idx);
615 ++idx;
616 }
617 return kTRUE;
618 }
619 fBulkTable = nullptr;
620 fSelecting = false;
621 return kFALSE;
622 }
623
624
625
629
630 KVNumberList database::get_integer_list(const TString& table, const TString& column, const TString& selection, const TString& anything_else)
631 {
632 // \note Only for INTEGER columns!
633 // Fill KVNumberList with all `DISTINCT` values of "column" (only 1 column name at a time) for given selection
634
636 if (select_data(table, column, selection, true, anything_else)) {
637 while (get_next_result()) {
638 result.Add((*this)[table][column].get_data<int>());
639 }
640 }
641 return result;
642 }
643
644
645
650
651 TString database::get_string_list(const TString& table, const TString& column, const TString& selection, const TString& anything_else)
652 {
653 // \note Only for TEXT columns!
654 // Fill TString with comma-separated list of values of "column" (only 1 column name at a time) for given selection
655 // \note Any NULL entries will be ignored
656
658 if (select_data(table, column, selection, false, anything_else)) {
659 while (get_next_result()) {
660 if ((*this)[table][column].is_null()) continue;
661 if (result != "") result += ",";
662 result += (*this)[table][column].get_data<TString>();
663 }
664 }
665 return result;
666 }
667
668
669
674
675 KVNameValueList database::get_name_value_list(const TString& tablename, const TString& name_column, const TString& value_column, const TString& selection, const TString& anything_else)
676 {
677 // Fill KVNameValueList with selected rows from table, adding for each row a parameter with the
678 // name contained in "name_column" (must be of type `TEXT`) and the value contained in "value_column"
679 // (can be `INTEGER`, `REAL`, or `TEXT`)
680
682 if (select_data(tablename, Form("%s,%s", name_column.Data(), value_column.Data()), selection, false, anything_else)) {
683 table& tb = (*this)[tablename];
684 column& nom = tb[name_column];
685 column& val = tb[value_column];
686 while (get_next_result()) {
687 result.SetValue(nom.get_data<TString>(), val.data());
688 }
689 }
690 return result;
691 }
692
693
694
698
699 TGraph* database::create_graph(const TString& tablename, const TString& Xcolumn, const TString& Ycolumn, const TString& selection)
700 {
701 // Create and fill a TGraph from values Xcolumn and Ycolumn in table,
702 // using the selection if required
703
704 if (select_data(tablename, Form("%s,%s", Xcolumn.Data(), Ycolumn.Data()), selection)) {
705 TGraph* g = new TGraph;
706 int i = 0;
707 table& tb = (*this)[tablename];
708 column& Xcol = tb[Xcolumn];
709 column& Ycol = tb[Ycolumn];
710 while (get_next_result()) {
711 g->SetPoint(i++, Xcol.get_data<double>(), Ycol.get_data<double>());
712 }
713 return g;
714 }
715 return nullptr;
716 }
717
718
719
722
724 {
725 // Delete all data from table
727 }
728
729
730
738
739 int database::count(const TString& table, const TString& column, const TString& selection, bool distinct) const
740 {
741 // Returns number of rows in table for which selection holds true:
742 //
743 // + if column="*" all rows are included
744 // + if a column name is given, only rows with a non-NULL value for column are counted
745 // + if distinct=false, count all rows including those with the same value of column
746 // + if distinct=true, count the number of different values of column
747
748 TString qry = "SELECT count(";
749 if (distinct) qry += "DISTINCT ";
750 qry += Form("\"%s\"", column.Data());
751 qry += ") FROM '";
752 qry += table;
753 qry += "'";
754 if (selection != "") {
755 qry += " WHERE ";
756 qry += selection;
757 }
758
759 std::unique_ptr<TSQLResult> result(fDBserv->Query(qry));
760 std::unique_ptr<TSQLRow> row(result->Next());
761 TString number = row->GetField(0);
762 return number.Atoi();
763 }
764
765
766
775
776 bool database::update(const TString& table, const TString& columns, const TString& selection)
777 {
778 // update the given columns of an entry in the table corresponding to selection (if given)
779 // the current values of the data members of the columns will be used
780 //
781 // This is equivalent to
782 //~~~~
783 // UPDATE [table] SET col1=newval,col2=newval,... [WHERE [selection]]
784 //~~~~
785
786 if (fInserting) {
787 Error("database::update",
788 "data insertion in progress; call end_data_insertion() before doing anything else");
789 return false;
790 }
791 if (fSelecting) {
792 Error("database::update",
793 "data retrieval in progress; call get_next_result() until it returns false before doing anything else");
794 return false;
795 }
796
797 fBulkTable = &fTables[table.Data()];
798 TString query = Form("UPDATE \"%s\" SET ", table.Data());
799 int ncol = fBulkTable->number_of_columns();
800 int idx = 0;
801 for (int i = 0; i < ncol; ++i) {
802 if (columns.Contains((*fBulkTable)[i].name())) {
803 if (idx) query += ",";
804 query += Form("\"%s\"", (*fBulkTable)[i].name());
805 query += "=?";
806 ++idx;
807 }
808 }
809 if (selection != "") query += Form(" WHERE %s", selection.Data());
810 //std::cout << query << std::endl;
811 fSQLstmt.reset(fDBserv->Statement(query));
812 fSQLstmt->NextIteration();
813 idx = 0;
814 for (int i = 0; i < ncol; ++i) {
815 if (columns.Contains((*fBulkTable)[i].name())) {
816 (*fBulkTable)[i].set_data_in_statement(fSQLstmt.get(), idx);
817 ++idx;
818 }
819 }
820 return (fSQLstmt->Process());
821 }
822
823
824
833
834 void database::delete_data(const TString& table, const TString& selection)
835 {
836 // delete rows from the table corresponding to selection
837 //
838 // This is equivalent to
839 //~~~~
840 // DELETE FROM [table] WHERE [selection]
841 //~~~~
842 // With no selection, deletes all rows of table (clear_table())
843
844 TString query = Form("DELETE FROM \"%s\"", table.Data());
845 if (selection != "") query += Form(" WHERE %s", selection.Data());
846 fDBserv->Exec(query);
847 }
848
849
850
854
855 column& database::add_column(const TString& table, const TString& name, const TString& type)
856 {
857 // add column to existing table
858 // \returns reference to new column
859 TString query = Form("ALTER TABLE \"%s\" ADD COLUMN \"%s\" %s", table.Data(), name.Data(), type.Data());
860 fDBserv->Exec(query);
861 return (*this)[table].add_column(name, type);
862 }
863
864
865
869
871 {
872 // add to table any columns which are defined in the list but don't exist
873 // \note cannot be called during data insertion or retrieval!!!
874
875 if (fInserting) {
876 Error("database::add_missing_columns",
877 "data insertion in progress; call end_data_insertion() before doing anything else");
878 return;
879 }
880 if (fSelecting) {
881 Error("database::add_missing_columns",
882 "data retrieval in progress; call get_next_result() until it returns false before doing anything else");
883 return;
884 }
885 int ipar = l.GetNpar();
886 table& tab = (*this)[_table_];
887 for (int i = 0; i < ipar; ++i) {
888 KVNamedParameter* par = l.GetParameter(i);
889 if (!tab.has_column(par->GetName())) add_column(_table_, par->GetName(), par->GetSQLType());
890 }
891 }
892
893
894
902
903 void database::copy_table_data(const TString& source, const TString& destination, const TString& columns, const TString& selection)
904 {
905 // Copy all selected data in 'source' table to 'destination'
906 //
907 // If the columns of the two tables are not identical, specify the columns to copy in 'columns'
908 // (comma-separated list)
909 // \note SQLite will not allow copy if the number of selected columns from 'source' is not
910 // exactly equal to the number of columns in 'destination'
911
912 TString COLUMNS = columns;
913 if (COLUMNS != "*") {
914 // quote all column names
915 COLUMNS = "";
916 KVString _columns(columns);
917 _columns.Begin(",");
918 while (!_columns.End()) {
919 if (COLUMNS != "") COLUMNS += ", ";
920 COLUMNS += Form("\"%s\"", _columns.Next(kTRUE).Data());
921 }
922 }
923 TString query = Form("INSERT INTO \"%s\" SELECT %s FROM %s", destination.Data(), COLUMNS.Data(), source.Data());
924 if (selection != "") query += Form(" WHERE %s", selection.Data());
925 fDBserv->Exec(query);
926 }
927
928
929
931
939
940
941
943
944 const char* column::_type()
945 {
946 return inv_type_map[fNameType.second];
947 }
948
949
950
952
953 template<> void column::set_data(const KVNamedParameter& x)
954 {
955 fData.Set(x.GetName(), x);
956 fIsNull = false;
957 }
958
959
960
966
968 {
969 // set value of parameter in SQLite statement corresponding to this column
970 // \param idx if given, use it as the statement parameter index instead of
971 // the column's index in the table (case where not all columns are treated
972 // in the statement)
973
974 if (idx < 0) idx = index();
975 if (fIsNull) {
976 // null parameter
977 s->SetNull(idx);
978 return;
979 }
980 switch (type()) {
982 s->SetDouble(idx, fData.GetDouble());
983 break;
985 s->SetInt(idx, fData.GetInt());
986 break;
988 s->SetString(idx, fData.GetString(), -1);
989 break;
991 s->SetBinary(idx, fBlob, fBlobSize);
992 break;
993 default:
994 break;
995 }
996 }
997
998
1009
1011 {
1012 // set value of column according to value of parameter in statement
1013 //
1014 // any column which has a NULL value will be given value 0, 0.0 or ""
1015 // (for `INTEGER`, `REAL` or `TEXT` type, respectively): use column::is_null()
1016 // to check if this corresponds to a null column value.
1017 //
1018 // \param idx if given, use it as the statement parameter index instead of
1019 // the column's index in the table (case where not all columns are treated
1020 // in the statement)
1021
1022 if (idx < 0) idx = index();
1023 fIsNull = s->IsNull(idx);
1024 switch (type()) {
1026 fData.Set(fIsNull ? 0.0 : s->GetDouble(idx));
1027 break;
1029 fData.Set(fIsNull ? 0 : s->GetInt(idx));
1030 break;
1032 fData.Set(fIsNull ? "" : s->GetString(idx));
1033 break;
1035 if (fIsNull) {
1036 fBlobSize = 0;
1037 }
1038 else {
1039 if (!fBlob) fBlob = (void*) new unsigned char[256];
1040 s->GetBinary(idx, fBlob, fBlobSize);
1041 }
1042 break;
1043 default:
1044 break;
1045 }
1046 }
1047
1048
1049
1053
1054 void column::set_foreign_key(const TString& _table, const TString& _column)
1055 {
1056 // declare this column to be a foreign key i.e. linked to the given
1057 // _column name in another _table
1058 fForeignKey = true;
1059 fFKtable = _table;
1060 fFKcolumn = _column;
1061 }
1062
1063
1064
1068
1069 void column::set_foreign_key(const table& _table, const column& _column)
1070 {
1071 // declare this column to be a foreign key i.e. linked to the given
1072 // _column name in another _table
1073 fForeignKey = true;
1074 fFKtable = _table.name();
1075 fFKcolumn = _column.name();
1076 }
1077
1078
1079
1081
1089
1090
1091
1094
1096 {
1097 // print list of columns
1098 std::cout << "Columns in table:" << std::endl;
1099#ifdef WITH_CPP11
1100 for (auto it = fColumns.begin(); it != fColumns.end(); ++it) {
1101#else
1102 for (std::vector<KVSQLite::column>::const_iterator it = fColumns.begin(); it != fColumns.end(); ++it) {
1103#endif
1104 std::cout << "\t" << it->name() << " [" << it->type_name() << "]" << std::endl;
1105 }
1106 }
1107
1108
1109
1114
1116 {
1117 // add column to table
1118 // \return reference to added column.
1119 // \note cannot be used for existing table in database: see database::add_column()
1120 fColumns.push_back(c);
1121 fColMap[c.name()] = c.index();
1122 fColumns.back().set_table(name());
1123 return fColumns.back();
1124 }
1125
1126
1127
1132
1134 {
1135 // add column to table
1136 // \return reference to added column
1137 // \note cannot be used for existing table in database: see database::add_column()
1138 return add_column(name, type_map[type]);
1139 }
1140
1141
1142
1151
1153 {
1154 // add a PRIMARY KEY column to the table
1155 // \returns reference to primary key (cannot be modified)
1156 //
1157 // \note by default this is an `INTEGER` type column
1158 //
1159 // \note as it is auto-incremented with each inserted row, it should not
1160 // be included in TSQLStatement used to write data to db
1161
1163 c.set_constraint("PRIMARY KEY");
1164 return c;
1165 }
1166
1167
1168
1176
1177 const column& table::add_foreign_key(const TString& other_table, const TString& other_column)
1178 {
1179 // add a foreign key to the table, which is an INTEGER reference to
1180 // another column in another table
1181 // \returns reference to key (cannot be modified)
1182 //
1183 // \note as foreign keys are only really useful if they have the same name in the child and parent tables,
1184 // we set the name of the foreign key by default to that of the other_column
1185
1187 c.set_foreign_key(other_table, other_column);
1188 return c;
1189 }
1190
1191
1192
1200
1201 const column& table::add_foreign_key(const table& other_table, const column& other_column)
1202 {
1203 // add a foreign key to the table, which is an INTEGER reference to
1204 // another column in another table.
1205 // \returns reference to key (cannot be modified)
1206 //
1207 // \note as foreign keys are only really useful if they have the same name in the child and parent tables,
1208 // we set the name of the foreign key by default to that of the other_column
1209
1211 c.set_foreign_key(other_table, other_column);
1212 return c;
1213 }
1214
1215
1216
1220
1222 {
1223 // make sure that all parameters in the list have corresponding columns in the table
1224 // \returns the number of columns to be added
1225
1226 int ncols = 0;
1227 int ipar = l.GetNpar();
1228 for (int i = 0; i < ipar; ++i) {
1229 KVNamedParameter* par = l.GetParameter(i);
1230 if (!has_column(par->GetName())) ncols++;
1231 }
1232 return ncols;
1233 }
1234
1235
1236
1243
1244 void table::prepare_data(const KVNameValueList& l, const KVNamedParameter* null_value)
1245 {
1246 // fill all columns in table with data contained in KVNameValueList parameters having the same name.
1247 //
1248 // any columns which do not appear in the KVNameValueList (except for PRIMARY KEY) will be set to 'null'
1249 //
1250 // if required, any parameters with the same type&value as "null_value" will be set to 'null' too
1251
1252 for (int i = 0; i < number_of_columns(); ++i) {
1253 KVNamedParameter* p = l.FindParameter((*this)[i].name());
1254 if (p && !(null_value && p->HasSameValueAs(*null_value)))
1255 (*this)[i].set_data(*p);
1256 else
1257 (*this)[i].set_null();
1258 }
1259 }
1260
1261
1262
1265
1267 {
1268 // set the value of all columns in the table to NULL
1269 for (int i = 0; i < number_of_columns(); ++i) {
1270 (*this)[i].set_null();
1271 }
1272 }
1273
1274
1275
1281
1282 TString table::get_column_names(const TString& exclude, const TString& delim) const
1283 {
1284 // Return a comma-separated list of the colum names
1285 //
1286 // \param[in] delim separator to use in list (default: ",")
1287 // \param[in] exclude list of column names to exclude from list
1288
1289 TString namelist;
1290 int added = 0;
1291 for (int i = 0; i < number_of_columns(); ++i) {
1292 TString name = (*this)[i].name();
1293 if (exclude.Contains(name)) continue;
1294 if (added) namelist += delim;
1295 namelist += name;
1296 ++added;
1297 }
1298 return namelist;
1299 }
1300
1301
1302 //____________________________________________________________________________//
1303
1304}
1305
ROOT::R::TRInterface & r
#define f(i)
#define c(i)
constexpr Bool_t kFALSE
constexpr Bool_t kTRUE
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t g
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
char name[80]
char * Form(const char *fmt,...)
R__EXTERN TSystem * gSystem
Handles lists of named parameters with different types, a list of KVNamedParameter objects.
A generic named parameter storing values of different types.
const Char_t * GetString() const
void Set(const char *, const char *)
const Char_t * GetSQLType() const
Double_t GetDouble() const
Strings used to represent a set of ranges of values.
Long_t fBlobSize
binary data
Definition SQLiteDB.h:128
void set_data_in_statement(TSQLStatement *, int idx=-1) const
Definition SQLiteDB.cpp:967
std::pair< TString, KVSQLite_column_type > fNameType
Definition SQLiteDB.h:122
const char * _type()
Definition SQLiteDB.cpp:944
void set_foreign_key(const TString &_table, const TString &_column)
TString fFKcolumn
Definition SQLiteDB.h:132
KVNamedParameter fData
Definition SQLiteDB.h:126
const KVNamedParameter & data() const
Definition SQLiteDB.h:249
T get_data() const
Definition SQLiteDB.h:254
KVSQLite_column_type type() const
Definition SQLiteDB.h:158
int index() const
Definition SQLiteDB.h:177
const char * name() const
Definition SQLiteDB.h:154
TString fFKtable
Definition SQLiteDB.h:131
static std::map< KVSQLite::column_type::types, TString > inv_type_map
Definition SQLiteDB.h:125
TString fConstraint
Definition SQLiteDB.h:123
void set_data(const T &x)
Definition SQLiteDB.h:187
const char * get_declaration() const
return declaration for column, including type & constraint
Definition SQLiteDB.cpp:360
void set_data_from_statement(TSQLStatement *s, int idx=-1) const
void set_constraint(const TString &c)
Definition SQLiteDB.h:226
const char * type_name() const
Definition SQLiteDB.h:162
Interface to ROOT SQLite database backend.
Definition SQLiteDB.h:401
void copy_table_data(const TString &source, const TString &destination, const TString &columns="*", const TString &selection="")
Definition SQLiteDB.cpp:903
std::list< const column * > fSQLstmtCols
Definition SQLiteDB.h:405
int count(const TString &table, const TString &column="*", const TString &selection="", bool distinct=false) const
Definition SQLiteDB.cpp:739
TGraph * create_graph(const TString &tablename, const TString &Xcolumn, const TString &Ycolumn, const TString &selection="")
Definition SQLiteDB.cpp:699
std::unique_ptr< TSQLResult > SelectRowsFromTable(const TString &table, const TString &columns="*", const TString &condition="") const
Definition SQLiteDB.cpp:34
std::unique_ptr< TSQLStatement > fSQLstmt
Definition SQLiteDB.h:404
bool update(const TString &table, const TString &columns, const TString &selection="")
Definition SQLiteDB.cpp:776
void delete_data(const TString &table, const TString &selection="")
Definition SQLiteDB.cpp:834
void show_tables() const
print list of tables
Definition SQLiteDB.cpp:84
column & add_column(const TString &table, const TString &name, const TString &type)
Definition SQLiteDB.cpp:855
void print_selection(const TString &table, const TString &columns, const TString &condition, int column_width=20) const
Print on stdout contents of database.
Definition SQLiteDB.cpp:192
std::unique_ptr< TSQLiteServer > fDBserv
Definition SQLiteDB.h:402
void open(const TString &dbfile)
Definition SQLiteDB.cpp:110
void end_data_insertion()
Definition SQLiteDB.cpp:433
bool select_data(const TString &tables, const TString &columns="*", const TString &selection="", bool distinct=false, const TString &anything_else="") const
Definition SQLiteDB.cpp:493
KVNameValueList get_name_value_list(const TString &table, const TString &name_column, const TString &value_column, const TString &selection="", const TString &anything_else="")
Definition SQLiteDB.cpp:675
bool get_next_result() const
Definition SQLiteDB.cpp:595
TString get_string_list(const TString &table, const TString &column, const TString &selection="", const TString &anything_else="")
Definition SQLiteDB.cpp:651
void Dump() const
Print on stdout contents of database.
Definition SQLiteDB.cpp:171
std::unordered_map< std::string, KVSQLite::table > fTables
Definition SQLiteDB.h:403
void add_table(const table &)
Definition SQLiteDB.cpp:219
void PrintResults(TSQLResult *tabent, int column_width=20) const
Definition SQLiteDB.cpp:143
bool prepare_data_insertion(const TString &)
Definition SQLiteDB.cpp:269
void clear_table(const TString &name)
Delete all data from table.
Definition SQLiteDB.cpp:723
void print_selected_data(const TString &tables, const TString &columns="*", const TString &selection="", bool distinct=false, const TString &anything_else="")
Print out results of a call to select_data().
Definition SQLiteDB.cpp:458
void read_table_infos()
initialise map of database tables from existing database
Definition SQLiteDB.cpp:52
void add_missing_columns(const TString &table, const KVNameValueList &l)
Definition SQLiteDB.cpp:870
KVNumberList get_integer_list(const TString &table, const TString &column, const TString &selection="", const TString &anything_else="")
Definition SQLiteDB.cpp:630
bool is_temporary() const
Definition SQLiteDB.h:332
const column & add_foreign_key(const TString &other_table, const TString &other_column)
std::vector< KVSQLite::column > fColumns
Definition SQLiteDB.h:277
int check_columns(const KVNameValueList &)
const column & add_primary_key(const TString &name)
const char * get_insert_command() const
Definition SQLiteDB.cpp:336
static std::map< TString, KVSQLite::column_type::types > type_map
Definition SQLiteDB.h:279
const char * name() const
Definition SQLiteDB.h:298
column & add_column(const KVSQLite::column &c)
TString get_column_names(const TString &exclude="", const TString &delim=",") const
int number_of_columns() const
Definition SQLiteDB.h:388
bool has_column(const TString &name) const
Definition SQLiteDB.h:359
void prepare_data(const KVNameValueList &, const KVNamedParameter *=nullptr)
void show_columns() const
print list of columns
KVSQLite_insert_mode fInsert
Definition SQLiteDB.h:276
void set_all_columns_null()
set the value of all columns in the table to NULL
std::unordered_map< std::string, int > fColMap
Definition SQLiteDB.h:278
Extension of ROOT TString class which allows backwards compatibility with ROOT v3....
Definition KVString.h:73
void Begin(TString delim) const
Definition KVString.cpp:565
Bool_t End() const
Definition KVString.cpp:634
KVString Next(Bool_t strip_whitespace=kFALSE) const
Definition KVString.cpp:695
const char * GetName() const override
virtual const char * GetName() const
virtual const char * GetFieldName(Int_t field)=0
virtual TSQLRow * Next()=0
virtual Int_t GetFieldCount()=0
static TSQLServer * Connect(const char *db, const char *uid, const char *pw)
Int_t Atoi() const
const char * Data() const
void Form(const char *fmt,...)
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
virtual char * ExpandPathName(const char *path)
Double_t x[n]
void Error(const char *location, const char *fmt,...)
TLine l
ClassImp(TPyArg)