KaliVeda
Toolkit for HIC analysis
KVSQLiteServer.cxx
1 // @(#)root/sqlite:$Id$
2 // Author: o.freyermuth <o.f@cern.ch>, 01/06/2013
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2013, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 #include "KVSQLiteServer.h"
13 #include "KVSQLiteResult.h"
14 #include "KVSQLiteStatement.h"
15 #include "TSQLColumnInfo.h"
16 #include "TList.h"
17 #include "TSQLTableInfo.h"
18 #include "TSQLRow.h"
19 
20 #include <sqlite3.h>
21 
22 #include <thread>
23 #include <chrono>
24 using namespace std::chrono_literals;
25 
26 ClassImp(KVSQLiteServer);
27 
36 
37 
39 
40 KVSQLiteServer::KVSQLiteServer(const char* db, const char* /*uid*/, const char* /*pw*/)
41 {
42  fSQLite = nullptr;
43  fSrvInfo = "SQLite ";
44  fSrvInfo += sqlite3_libversion();
45 
46  if (strncmp(db, "sqlite://", 9)) {
47  TString givenProtocol(db, 9); // this TString-constructor allocs len+1 and does \0 termination already.
48  Error("KVSQLiteServer", "protocol in db argument should be sqlite it is %s",
49  givenProtocol.Data());
50  MakeZombie();
51  return;
52  }
53 
54  const char* dbase = db + 9;
55 
56 #ifndef SQLITE_OPEN_URI
57 #define SQLITE_OPEN_URI 0x00000000
58 #endif
59 #if SQLITE_VERSION_NUMBER >= 3005000
60  Int_t error = sqlite3_open_v2(dbase, &fSQLite, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI, NULL);
61 #else
62  Int_t error = sqlite3_open(dbase, &fSQLite);
63 #endif
64 
65  if (error == 0) {
66  // Set members of the abstract interface
67  fType = "SQLite";
68  fHost = "";
69  fDB = dbase;
70  // fPort != -1 means we are 'connected'
71  fPort = 0;
72  }
73  else {
74  Error("KVSQLiteServer", "opening of %s failed with error: %d %s", dbase, sqlite3_errcode(fSQLite), sqlite3_errmsg(fSQLite));
75  sqlite3_close(fSQLite);
76  MakeZombie();
77  }
78 
79 }
80 
81 
84 
85 
87 
88 KVSQLiteServer::~KVSQLiteServer()
89 {
90  if (IsConnected()) {
91  sqlite3_close(fSQLite);
92  }
93 }
94 
95 
98 
99 
101 
102 void KVSQLiteServer::Close(Option_t*)
103 {
104  if (!fSQLite) {
105  return;
106  }
107 
108  if (IsConnected()) {
109  sqlite3_close(fSQLite);
110  // Mark as disconnected:
111  fPort = -1;
112  fSQLite = nullptr;
113  }
114 }
115 
116 
120 
121 
123 
124 Bool_t KVSQLiteServer::StartTransaction()
125 {
126  return Exec("BEGIN TRANSACTION");
127 }
128 
129 
132 
133 
135 
136 Bool_t KVSQLiteServer::HasTransactionInFlight()
137 {
138  if (!fSQLite)
139  return kFALSE;
140 
141  return sqlite3_get_autocommit(fSQLite) == 0;
142 }
143 
144 
145 
149 
150 
152 
153 Bool_t KVSQLiteServer::Commit()
154 {
155  return Exec("COMMIT TRANSACTION");
156 }
157 
158 
162 
163 
165 
166 Bool_t KVSQLiteServer::Rollback()
167 {
168  return Exec("ROLLBACK TRANSACTION");
169 }
170 
171 
176 
177 
179 
180 TSQLResult* KVSQLiteServer::Query(const char* sql)
181 {
182  if (!IsConnected()) {
183  Error("Query", "not connected");
184  return nullptr;
185  }
186 
187  sqlite3_stmt* preparedStmt = nullptr;
188  const char* tail = nullptr;
189  ClearError();
190  // -1 as we read until we encounter a \0.
191 #if SQLITE_VERSION_NUMBER >= 3005000
192  int retVal = sqlite3_prepare_v2(fSQLite, sql, -1, &preparedStmt, &tail);
193 #else
194  int retVal = sqlite3_prepare(fSQLite, sql, -1, &preparedStmt, &tail);
195 #endif
196  if (retVal != SQLITE_OK) {
197  SetError(retVal,sqlite3_errmsg(fSQLite),"Query");
198  Info("Query","Query was:%s",sql);
199  return nullptr;
200  }
201  if (tail && tail[0] != '\0')
202  Warning("Query", "Don't use multiple queries, '%s' query was ignored", tail);
203 
204  return new KVSQLiteResult(preparedStmt);
205 }
206 
207 
211 
212 
214 
215 Bool_t KVSQLiteServer::Exec(const char* sql)
216 {
217  if (!IsConnected()) {
218  Error("Exec", "not connected");
219  return kFALSE;
220  }
221 
222  ClearError();
223  int ret = sqlite3_exec(fSQLite, sql, NULL, NULL, NULL);
224  if (ret != SQLITE_OK) {
225  SetError(ret,sqlite3_errmsg(fSQLite),"Exec");
226  return kFALSE;
227  }
228  return kTRUE;
229 }
230 
231 
232 
236 
237 
239 
240 Int_t KVSQLiteServer::SelectDataBase(const char* /*dbname*/)
241 {
242  Error("SelectDataBase", "SelectDataBase command makes no sense for SQLite!");
243  return -1;
244 }
245 
246 
250 
251 
253 
254 TSQLResult* KVSQLiteServer::GetDataBases(const char* /*wild*/)
255 {
256  Error("GetDataBases", "GetDataBases command makes no sense for SQLite!");
257  return nullptr;
258 }
259 
260 
266 
267 
269 
270 TSQLResult* KVSQLiteServer::GetTables(const char* /*dbname*/, const char* wild)
271 {
272  if (!IsConnected()) {
273  Error("GetTables", "not connected");
274  return nullptr;
275  }
276 
277  TString sql = "SELECT name FROM sqlite_master where type='table'";
278  if (wild)
279  sql += Form(" AND name LIKE '%s'", wild);
280 
281  return Query(sql);
282 }
283 
284 
285 
287 
288 TList* KVSQLiteServer::GetTablesList(const char* wild)
289 {
290  auto l = TSQLServer::GetTablesList(wild);
291  if(!l)
292  {
293  // if database is locked, try again until it works
294  if(IsLocked())
295  {
296  int i=2;
297  do
298  {
299  Info("GetTablesList","Database is locked. Try again in 50ms...");
300  std::this_thread::sleep_for(50ms);
301  Info("GetTablesList", "Try number %d...",i);
303  }
304  while(!l && IsLocked() && (i<6));
305  if(l && !IsLocked())
306  Info("GetTablesList","...database access successful!");
307  }
308  }
309  return l;
310 }
311 
312 
321 
322 
324 
325 TSQLResult* KVSQLiteServer::GetColumns(const char* /*dbname*/, const char* table,
326  const char* wild)
327 {
328  if (!IsConnected()) {
329  Error("GetColumns", "not connected");
330  return nullptr;
331  }
332 
333  if (wild) {
334  Error("GetColumns", "Not implementable for SQLite as a query with wildcard, use GetFieldNames() after SELECT instead!");
335  return nullptr;
336  }
337  else {
338  TString sql = Form("PRAGMA table_info('%s')", table);
339  return Query(sql);
340  }
341 }
342 
343 
347 
348 
350 
351 TSQLTableInfo* KVSQLiteServer::GetTableInfo(const char* tablename)
352 {
353  if (!IsConnected()) {
354  Error("GetTableInfo", "not connected");
355  return nullptr;
356  }
357 
358  if (!tablename || (*tablename == 0)) return nullptr;
359 
360  TSQLResult* columnRes = GetColumns("", tablename);
361 
362  if (columnRes == nullptr) {
363  Error("GetTableInfo", "could not query columns");
364  return nullptr;
365  }
366 
367  TList* lst = nullptr;
368 
369  TSQLRow* columnRow;
370 
371  while ((columnRow = columnRes->Next()) != nullptr) {
372  if (!lst) {
373  lst = new TList();
374  }
375 
376  // Field 3 is 'notnull', i.e. if it is 0, column is nullable
377  Bool_t isNullable = (strcmp(columnRow->GetField(3), "0") == 0);
378 
379  lst->Add(new TSQLColumnInfo(columnRow->GetField(1), // column name
380  columnRow->GetField(2), // column type name
381  isNullable, // isNullable defined above
382  -1, // SQLite is totally free about types
383  -1, // SQLite imposes no declarable size-limits
384  -1, // Field length only available querying the field
385  -1, // no data scale in SQLite
386  -1)); // SQLite does not enforce any sign(s)
387  delete columnRow;
388  }
389  delete columnRes;
390 
391  // lst == NULL is ok as TSQLTableInfo accepts and handles this
392  TSQLTableInfo* info = new TSQLTableInfo(tablename,
393  lst);
394 
395  return info;
396 }
397 
398 
402 
403 
405 
406 Int_t KVSQLiteServer::CreateDataBase(const char* /*dbname*/)
407 {
408  Error("CreateDataBase", "CreateDataBase command makes no sense for SQLite!");
409  return -1;
410 }
411 
412 
416 
417 
419 
420 Int_t KVSQLiteServer::DropDataBase(const char* /*dbname*/)
421 {
422  Error("DropDataBase", "DropDataBase command makes no sense for SQLite!");
423  return -1;
424 }
425 
426 
430 
431 
433 
434 Int_t KVSQLiteServer::Reload()
435 {
436  if (!IsConnected()) {
437  Error("Reload", "not connected");
438  return -1;
439  }
440 
441  Error("Reload", "not implemented");
442  return 0;
443 }
444 
445 
449 
450 
452 
453 Int_t KVSQLiteServer::Shutdown()
454 {
455  if (!IsConnected()) {
456  Error("Shutdown", "not connected");
457  return -1;
458  }
459 
460  Error("Shutdown", "not implemented");
461  return -1;
462 }
463 
464 
470 
471 
473 
474 Bool_t KVSQLiteServer::HasStatement() const
475 {
476  return kTRUE;
477 }
478 
479 
482 
483 
485 
486 TSQLStatement* KVSQLiteServer::Statement(const char* sql, Int_t)
487 {
488  if (!sql || !*sql) {
489  SetError(-1, "no query string specified", "Statement");
490  return nullptr;
491  }
492 
493  if (!IsConnected()) {
494  Error("Statement", "not connected");
495  return nullptr;
496  }
497 
498  sqlite3_stmt* preparedStmt = nullptr;
499  const char* tail = nullptr;
500 
501  ClearError();
502 
503  // -1 as we read until we encounter a \0.
504 #if SQLITE_VERSION_NUMBER >= 3005000
505  int retVal = sqlite3_prepare_v2(fSQLite, sql, -1, &preparedStmt, &tail);
506 #else
507  int retVal = sqlite3_prepare(fSQLite, sql, -1, &preparedStmt, &tail);
508 #endif
509  if (retVal != SQLITE_OK) {
510  SetError(retVal,sqlite3_errmsg(fSQLite),"Statement");
511  return nullptr;
512  }
513  if (tail && tail[0] != '\0')
514  Warning("Statement", "Don't use multiple statements, '%s' statement was ignored", tail);
515 
516  SQLite3_Stmt_t* stmt = new SQLite3_Stmt_t;
517  stmt->fConn = fSQLite;
518  stmt->fRes = preparedStmt;
519 
520  return new KVSQLiteStatement(stmt);
521 }
522 
523 
526 
527 
529 
530 const char* KVSQLiteServer::ServerInfo()
531 {
532  if (!IsConnected()) {
533  Error("ServerInfo", "not connected");
534  return nullptr;
535  }
536 
537  return fSrvInfo.Data();
538 }
539 
540 
541 
543 
544 bool KVSQLiteServer::IsLocked() const
545 {
546  return GetErrorCode()==SQLITE_BUSY;
547 }
548 
549 
550 
552 
553 bool KVSQLiteServer::IsOK() const
554 {
555  return GetErrorCode()==SQLITE_OK;
556 }
557 
558 
int Int_t
bool Bool_t
constexpr Bool_t kFALSE
constexpr Bool_t kTRUE
const char Option_t
char * Form(const char *fmt,...)
void Add(TObject *obj) override
virtual TSQLRow * Next()=0
virtual const char * GetField(Int_t field)=0
virtual TList * GetTablesList(const char *wild=nullptr)
CPYCPPYY_EXTERN bool Exec(const std::string &cmd)
void Error(const char *location, const char *fmt,...)
void Info(const char *location, const char *fmt,...)
void Warning(const char *location, const char *fmt,...)
sqlite3_stmt * fRes
sqlite3 * fConn
TLine l
ClassImp(TPyArg)