Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TSQLiteServer.cxx
Go to the documentation of this file.
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 "TSQLiteServer.h"
13#include "TSQLiteResult.h"
14#include "TSQLiteStatement.h"
15#include "TSQLColumnInfo.h"
16#include "TList.h"
17#include "TSQLTableInfo.h"
18#include "TSQLRow.h"
19
20#include <sqlite3.h>
21
23
24////////////////////////////////////////////////////////////////////////////////
25/// Open a connection to an SQLite DB server. The db arguments should be
26/// of the form "sqlite://<database>", e.g.:
27/// "sqlite://test.sqlite" or "sqlite://:memory:" for a temporary database
28/// in memory.
29/// Note that for SQLite versions >= 3.7.7 the full string behind
30/// "sqlite://" is handed to sqlite3_open_v2() with SQLITE_OPEN_URI activated,
31/// so all URI accepted by it can be used.
32
33TSQLiteServer::TSQLiteServer(const char *db, const char* /*uid*/, const char* /*pw*/)
34{
35 fSQLite = nullptr;
36 fSrvInfo = "SQLite ";
37 fSrvInfo += sqlite3_libversion();
38
39 if (strncmp(db, "sqlite://", 9)) {
40 TString givenProtocol(db, 9); // this TString-constructor allocs len+1 and does \0 termination already.
41 Error("TSQLiteServer", "protocol in db argument should be sqlite it is %s",
42 givenProtocol.Data());
43 MakeZombie();
44 return;
45 }
46
47 const char *dbase = db + 9;
48
49#ifndef SQLITE_OPEN_URI
50#define SQLITE_OPEN_URI 0x00000000
51#endif
52#if SQLITE_VERSION_NUMBER >= 3005000
53 Int_t error = sqlite3_open_v2(dbase, &fSQLite, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_URI, NULL);
54#else
55 Int_t error = sqlite3_open(dbase, &fSQLite);
56#endif
57
58 if (error == 0) {
59 // Set members of the abstract interface
60 fType = "SQLite";
61 fHost = "";
62 fDB = dbase;
63 // fPort != -1 means we are 'connected'
64 fPort = 0;
65 } else {
66 Error("TSQLiteServer", "opening of %s failed with error: %d %s", dbase, sqlite3_errcode(fSQLite), sqlite3_errmsg(fSQLite));
67 sqlite3_close(fSQLite);
68 MakeZombie();
69 }
70
71}
72
73////////////////////////////////////////////////////////////////////////////////
74/// Close SQLite DB.
75
77{
78 if (IsConnected()) {
79 sqlite3_close(fSQLite);
80 }
81}
82
83////////////////////////////////////////////////////////////////////////////////
84/// Close connection to SQLite DB.
85
87{
88 if (!fSQLite) {
89 return;
90 }
91
92 if (IsConnected()) {
93 sqlite3_close(fSQLite);
94 // Mark as disconnected:
95 fPort = -1;
96 fSQLite = nullptr;
97 }
98}
99
100////////////////////////////////////////////////////////////////////////////////
101/// submit "BEGIN TRANSACTION" query to database
102/// return kTRUE, if successful
103
105{
106 return Exec("BEGIN TRANSACTION");
107}
108
109////////////////////////////////////////////////////////////////////////////////
110/// returns kTRUE when transaction is running
111
113{
114 if (!fSQLite)
115 return kFALSE;
116
117 return sqlite3_get_autocommit(fSQLite) == 0;
118}
119
120
121////////////////////////////////////////////////////////////////////////////////
122/// submit "COMMIT TRANSACTION" query to database
123/// return kTRUE, if successful
124
126{
127 return Exec("COMMIT TRANSACTION");
128}
129
130////////////////////////////////////////////////////////////////////////////////
131/// submit "ROLLBACK TRANSACTION" query to database
132/// return kTRUE, if successful
133
135{
136 return Exec("ROLLBACK TRANSACTION");
137}
138
139////////////////////////////////////////////////////////////////////////////////
140/// Execute SQL command. Result object must be deleted by the user.
141/// Returns a pointer to a TSQLResult object if successful, 0 otherwise.
142/// The result object must be deleted by the user.
143
145{
146 if (!IsConnected()) {
147 Error("Query", "not connected");
148 return nullptr;
149 }
150
151 sqlite3_stmt *preparedStmt = nullptr;
152
153 // -1 as we read until we encounter a \0.
154 // NULL because we do not check which char was read last.
155#if SQLITE_VERSION_NUMBER >= 3005000
156 int retVal = sqlite3_prepare_v2(fSQLite, sql, -1, &preparedStmt, nullptr);
157#else
158 int retVal = sqlite3_prepare(fSQLite, sql, -1, &preparedStmt, nullptr);
159#endif
160 if (retVal != SQLITE_OK) {
161 Error("Query", "SQL Error: %d %s", retVal, sqlite3_errmsg(fSQLite));
162 return nullptr;
163 }
164
165 return new TSQLiteResult(preparedStmt);
166}
167
168////////////////////////////////////////////////////////////////////////////////
169/// Execute SQL command which does not produce any result sets.
170/// Returns kTRUE if successful.
171
173{
174 if (!IsConnected()) {
175 Error("Exec", "not connected");
176 return kFALSE;
177 }
178
179 char *sqlite_err_msg;
180 int ret = sqlite3_exec(fSQLite, sql, NULL, NULL, &sqlite_err_msg);
181 if (ret != SQLITE_OK) {
182 Error("Exec", "SQL Error: %d %s", ret, sqlite_err_msg);
183 sqlite3_free(sqlite_err_msg);
184 return kFALSE;
185 }
186 return kTRUE;
187}
188
189
190////////////////////////////////////////////////////////////////////////////////
191/// Select a database. Always returns non-zero for SQLite,
192/// as only one DB exists per file.
193
195{
196 Error("SelectDataBase", "SelectDataBase command makes no sense for SQLite!");
197 return -1;
198}
199
200////////////////////////////////////////////////////////////////////////////////
201/// List all available databases. Always returns 0 for SQLite,
202/// as only one DB exists per file.
203
205{
206 Error("GetDataBases", "GetDataBases command makes no sense for SQLite!");
207 return nullptr;
208}
209
210////////////////////////////////////////////////////////////////////////////////
211/// List all tables in the specified database. Wild is for wildcarding
212/// "t%" list all tables starting with "t".
213/// Returns a pointer to a TSQLResult object if successful, 0 otherwise.
214/// The result object must be deleted by the user.
215
216TSQLResult *TSQLiteServer::GetTables(const char* /*dbname*/, const char *wild)
217{
218 if (!IsConnected()) {
219 Error("GetTables", "not connected");
220 return nullptr;
221 }
222
223 TString sql = "SELECT name FROM sqlite_master where type='table'";
224 if (wild)
225 sql += Form(" AND name LIKE '%s'", wild);
226
227 return Query(sql);
228}
229
230////////////////////////////////////////////////////////////////////////////////
231/// List all columns in specified table (database argument is ignored).
232/// Wild is for wildcarding "t%" list all columns starting with "t".
233/// Returns a pointer to a TSQLResult object if successful, 0 otherwise.
234/// The result object must be deleted by the user.
235/// For SQLite, this fails with wildcard, as the column names are not queryable!
236/// If no wildcard is used, the result of PRAGMA table_info(table) is returned,
237/// which contains the names in field 1.
238
239TSQLResult *TSQLiteServer::GetColumns(const char* /*dbname*/, const char* table,
240 const char* wild)
241{
242 if (!IsConnected()) {
243 Error("GetColumns", "not connected");
244 return nullptr;
245 }
246
247 if (wild) {
248 Error("GetColumns", "Not implementable for SQLite as a query with wildcard, use GetFieldNames() after SELECT instead!");
249 return nullptr;
250 } else {
251 TString sql = Form("PRAGMA table_info('%s')", table);
252 return Query(sql);
253 }
254}
255
256////////////////////////////////////////////////////////////////////////////////
257/// Produces SQL table info.
258/// Object must be deleted by user.
259
261{
262 if (!IsConnected()) {
263 Error("GetTableInfo", "not connected");
264 return nullptr;
265 }
266
267 if (!tablename || (*tablename==0)) return nullptr;
268
269 TSQLResult *columnRes = GetColumns("", tablename);
270
271 if (columnRes == nullptr) {
272 Error("GetTableInfo", "could not query columns");
273 return nullptr;
274 }
275
276 TList* lst = nullptr;
277
278 TSQLRow *columnRow;
279
280 while ((columnRow = columnRes->Next()) != nullptr) {
281 if (!lst) {
282 lst = new TList();
283 }
284
285 // Field 3 is 'notnull', i.e. if it is 0, column is nullable
286 Bool_t isNullable = (strcmp(columnRow->GetField(3), "0") == 0);
287
288 lst->Add(new TSQLColumnInfo(columnRow->GetField(1), // column name
289 columnRow->GetField(2), // column type name
290 isNullable, // isNullable defined above
291 -1, // SQLite is totally free about types
292 -1, // SQLite imposes no declarable size-limits
293 -1, // Field length only available querying the field
294 -1, // no data scale in SQLite
295 -1)); // SQLite does not enforce any sign(s)
296 delete columnRow;
297 }
298 delete columnRes;
299
300 // lst == NULL is ok as TSQLTableInfo accepts and handles this
301 TSQLTableInfo* info = new TSQLTableInfo(tablename,
302 lst);
303
304 return info;
305}
306
307////////////////////////////////////////////////////////////////////////////////
308/// Create a database. Always returns non-zero for SQLite,
309/// as it has only one DB per file.
310
312{
313 Error("CreateDataBase", "CreateDataBase command makes no sense for SQLite!");
314 return -1;
315}
316
317////////////////////////////////////////////////////////////////////////////////
318/// Drop (i.e. delete) a database. Always returns non-zero for SQLite,
319/// as it has only one DB per file.
320
321Int_t TSQLiteServer::DropDataBase(const char* /*dbname*/)
322{
323 Error("DropDataBase", "DropDataBase command makes no sense for SQLite!");
324 return -1;
325}
326
327////////////////////////////////////////////////////////////////////////////////
328/// Reload permission tables. Returns 0 if successful, non-zero
329/// otherwise. User must have reload permissions.
330
332{
333 if (!IsConnected()) {
334 Error("Reload", "not connected");
335 return -1;
336 }
337
338 Error("Reload", "not implemented");
339 return 0;
340}
341
342////////////////////////////////////////////////////////////////////////////////
343/// Shutdown the database server. Returns 0 if successful, non-zero
344/// otherwise. Makes no sense for SQLite, always returns -1.
345
347{
348 if (!IsConnected()) {
349 Error("Shutdown", "not connected");
350 return -1;
351 }
352
353 Error("Shutdown", "not implemented");
354 return -1;
355}
356
357////////////////////////////////////////////////////////////////////////////////
358/// We assume prepared statements work for all SQLite-versions.
359/// As we actually use the recommended sqlite3_prepare(),
360/// or, if possible, sqlite3_prepare_v2(),
361/// this already introduces the "compile time check".
362
364{
365 return kTRUE;
366}
367
368////////////////////////////////////////////////////////////////////////////////
369/// Produce TSQLiteStatement.
370
372{
373 if (!sql || !*sql) {
374 SetError(-1, "no query string specified", "Statement");
375 return nullptr;
376 }
377
378 if (!IsConnected()) {
379 Error("Statement", "not connected");
380 return nullptr;
381 }
382
383 sqlite3_stmt *preparedStmt = nullptr;
384
385 // -1 as we read until we encounter a \0.
386 // NULL because we do not check which char was read last.
387#if SQLITE_VERSION_NUMBER >= 3005000
388 int retVal = sqlite3_prepare_v2(fSQLite, sql, -1, &preparedStmt, NULL);
389#else
390 int retVal = sqlite3_prepare(fSQLite, sql, -1, &preparedStmt, NULL);
391#endif
392 if (retVal != SQLITE_OK) {
393 Error("Statement", "SQL Error: %d %s", retVal, sqlite3_errmsg(fSQLite));
394 return nullptr;
395 }
396
397 SQLite3_Stmt_t *stmt = new SQLite3_Stmt_t;
398 stmt->fConn = fSQLite;
399 stmt->fRes = preparedStmt;
400
401 return new TSQLiteStatement(stmt);
402}
403
404////////////////////////////////////////////////////////////////////////////////
405/// Return server info, must be deleted by user.
406
408{
409 if (!IsConnected()) {
410 Error("ServerInfo", "not connected");
411 return nullptr;
412 }
413
414 return fSrvInfo.Data();
415}
constexpr Bool_t kFALSE
Definition RtypesCore.h:101
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:377
#define SQLITE_OPEN_URI
char * Form(const char *fmt,...)
Formats a string in a circular formatting buffer.
Definition TString.cxx:2467
A doubly linked list.
Definition TList.h:38
void Add(TObject *obj) override
Definition TList.h:81
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:970
void MakeZombie()
Definition TObject.h:53
virtual TSQLRow * Next()=0
virtual const char * GetField(Int_t field)=0
TString fHost
Definition TSQLServer.h:45
void SetError(Int_t code, const char *msg, const char *method=nullptr)
set new values for error fields if method is specified, displays error message
Int_t fPort
Definition TSQLServer.h:47
TString fDB
Definition TSQLServer.h:46
virtual Bool_t IsConnected() const
Definition TSQLServer.h:93
TString fType
Definition TSQLServer.h:44
Int_t SelectDataBase(const char *dbname) final
Select a database.
TSQLStatement * Statement(const char *sql, Int_t=100) final
Produce TSQLiteStatement.
Bool_t HasStatement() const final
We assume prepared statements work for all SQLite-versions.
Int_t DropDataBase(const char *dbname) final
Drop (i.e.
TSQLResult * GetTables(const char *dbname, const char *wild=nullptr) final
List all tables in the specified database.
Bool_t Commit() final
submit "COMMIT TRANSACTION" query to database return kTRUE, if successful
TSQLResult * Query(const char *sql) final
Execute SQL command.
Bool_t HasTransactionInFlight() final
returns kTRUE when transaction is running
const char * ServerInfo() final
Return server info, must be deleted by user.
Bool_t Rollback() final
submit "ROLLBACK TRANSACTION" query to database return kTRUE, if successful
TSQLResult * GetColumns(const char *dbname, const char *table, const char *wild=nullptr) final
List all columns in specified table (database argument is ignored).
Int_t Shutdown() final
Shutdown the database server.
Bool_t Exec(const char *sql) final
Execute SQL command which does not produce any result sets.
Int_t Reload() final
Reload permission tables.
sqlite3 * fSQLite
TSQLResult * GetDataBases(const char *wild=nullptr) final
List all available databases.
Int_t CreateDataBase(const char *dbname) final
Create a database.
~TSQLiteServer()
Close SQLite DB.
void Close(Option_t *opt="") final
Close connection to SQLite DB.
TSQLiteServer(const char *db, const char *uid=nullptr, const char *pw=nullptr)
Open a connection to an SQLite DB server.
Bool_t StartTransaction() final
submit "BEGIN TRANSACTION" query to database return kTRUE, if successful
TSQLTableInfo * GetTableInfo(const char *tablename) final
Produces SQL table info.
Basic string class.
Definition TString.h:139
const char * Data() const
Definition TString.h:380
sqlite3_stmt * fRes