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 "START TRANSACTION" query to database
102/// return kTRUE, if successful
103
105{
106 return Exec("BEGIN TRANSACTION");
107}
108
109////////////////////////////////////////////////////////////////////////////////
110/// Execute SQL command. Result object must be deleted by the user.
111/// Returns a pointer to a TSQLResult object if successful, 0 otherwise.
112/// The result object must be deleted by the user.
113
115{
116 if (!IsConnected()) {
117 Error("Query", "not connected");
118 return 0;
119 }
120
121 sqlite3_stmt *preparedStmt = nullptr;
122
123 // -1 as we read until we encounter a \0.
124 // NULL because we do not check which char was read last.
125#if SQLITE_VERSION_NUMBER >= 3005000
126 int retVal = sqlite3_prepare_v2(fSQLite, sql, -1, &preparedStmt, NULL);
127#else
128 int retVal = sqlite3_prepare(fSQLite, sql, -1, &preparedStmt, NULL);
129#endif
130 if (retVal != SQLITE_OK) {
131 Error("Query", "SQL Error: %d %s", retVal, sqlite3_errmsg(fSQLite));
132 return 0;
133 }
134
135 return new TSQLiteResult(preparedStmt);
136}
137
138////////////////////////////////////////////////////////////////////////////////
139/// Execute SQL command which does not produce any result sets.
140/// Returns kTRUE if successful.
141
143{
144 if (!IsConnected()) {
145 Error("Exec", "not connected");
146 return kFALSE;
147 }
148
149 char *sqlite_err_msg;
150 int ret = sqlite3_exec(fSQLite, sql, NULL, NULL, &sqlite_err_msg);
151 if (ret != SQLITE_OK) {
152 Error("Exec", "SQL Error: %d %s", ret, sqlite_err_msg);
153 sqlite3_free(sqlite_err_msg);
154 return kFALSE;
155 }
156 return kTRUE;
157}
158
159
160////////////////////////////////////////////////////////////////////////////////
161/// Select a database. Always returns non-zero for SQLite,
162/// as only one DB exists per file.
163
165{
166 Error("SelectDataBase", "SelectDataBase command makes no sense for SQLite!");
167 return -1;
168}
169
170////////////////////////////////////////////////////////////////////////////////
171/// List all available databases. Always returns 0 for SQLite,
172/// as only one DB exists per file.
173
175{
176 Error("GetDataBases", "GetDataBases command makes no sense for SQLite!");
177 return 0;
178}
179
180////////////////////////////////////////////////////////////////////////////////
181/// List all tables in the specified database. Wild is for wildcarding
182/// "t%" list all tables starting with "t".
183/// Returns a pointer to a TSQLResult object if successful, 0 otherwise.
184/// The result object must be deleted by the user.
185
186TSQLResult *TSQLiteServer::GetTables(const char* /*dbname*/, const char *wild)
187{
188 if (!IsConnected()) {
189 Error("GetTables", "not connected");
190 return 0;
191 }
192
193 TString sql = "SELECT name FROM sqlite_master where type='table'";
194 if (wild)
195 sql += Form(" AND name LIKE '%s'", wild);
196
197 return Query(sql);
198}
199
200////////////////////////////////////////////////////////////////////////////////
201/// List all columns in specified table (database argument is ignored).
202/// Wild is for wildcarding "t%" list all columns starting with "t".
203/// Returns a pointer to a TSQLResult object if successful, 0 otherwise.
204/// The result object must be deleted by the user.
205/// For SQLite, this fails with wildcard, as the column names are not queryable!
206/// If no wildcard is used, the result of PRAGMA table_info(table) is returned,
207/// which contains the names in field 1.
208
209TSQLResult *TSQLiteServer::GetColumns(const char* /*dbname*/, const char* table,
210 const char* wild)
211{
212 if (!IsConnected()) {
213 Error("GetColumns", "not connected");
214 return 0;
215 }
216
217 if (wild) {
218 Error("GetColumns", "Not implementable for SQLite as a query with wildcard, use GetFieldNames() after SELECT instead!");
219 return nullptr;
220 } else {
221 TString sql = Form("PRAGMA table_info('%s')", table);
222 return Query(sql);
223 }
224}
225
226////////////////////////////////////////////////////////////////////////////////
227/// Produces SQL table info.
228/// Object must be deleted by user.
229
231{
232 if (!IsConnected()) {
233 Error("GetTableInfo", "not connected");
234 return 0;
235 }
236
237 if ((tablename==0) || (*tablename==0)) return nullptr;
238
239 TSQLResult *columnRes = GetColumns("", tablename);
240
241 if (columnRes == nullptr) {
242 Error("GetTableInfo", "could not query columns");
243 return nullptr;
244 }
245
246 TList* lst = nullptr;
247
248 TSQLRow *columnRow;
249
250 while ((columnRow = columnRes->Next()) != nullptr) {
251 if (!lst) {
252 lst = new TList();
253 }
254
255 // Field 3 is 'notnull', i.e. if it is 0, column is nullable
256 Bool_t isNullable = (strcmp(columnRow->GetField(3), "0") == 0);
257
258 lst->Add(new TSQLColumnInfo(columnRow->GetField(1), // column name
259 columnRow->GetField(2), // column type name
260 isNullable, // isNullable defined above
261 -1, // SQLite is totally free about types
262 -1, // SQLite imposes no declarable size-limits
263 -1, // Field length only available querying the field
264 -1, // no data scale in SQLite
265 -1)); // SQLite does not enforce any sign(s)
266 delete columnRow;
267 }
268 delete columnRes;
269
270 // lst == NULL is ok as TSQLTableInfo accepts and handles this
271 TSQLTableInfo* info = new TSQLTableInfo(tablename,
272 lst);
273
274 return info;
275}
276
277////////////////////////////////////////////////////////////////////////////////
278/// Create a database. Always returns non-zero for SQLite,
279/// as it has only one DB per file.
280
282{
283 Error("CreateDataBase", "CreateDataBase command makes no sense for SQLite!");
284 return -1;
285}
286
287////////////////////////////////////////////////////////////////////////////////
288/// Drop (i.e. delete) a database. Always returns non-zero for SQLite,
289/// as it has only one DB per file.
290
291Int_t TSQLiteServer::DropDataBase(const char* /*dbname*/)
292{
293 Error("DropDataBase", "DropDataBase command makes no sense for SQLite!");
294 return -1;
295}
296
297////////////////////////////////////////////////////////////////////////////////
298/// Reload permission tables. Returns 0 if successful, non-zero
299/// otherwise. User must have reload permissions.
300
302{
303 if (!IsConnected()) {
304 Error("Reload", "not connected");
305 return -1;
306 }
307
308 Error("Reload", "not implemented");
309 return 0;
310}
311
312////////////////////////////////////////////////////////////////////////////////
313/// Shutdown the database server. Returns 0 if successful, non-zero
314/// otherwise. Makes no sense for SQLite, always returns -1.
315
317{
318 if (!IsConnected()) {
319 Error("Shutdown", "not connected");
320 return -1;
321 }
322
323 Error("Shutdown", "not implemented");
324 return -1;
325}
326
327////////////////////////////////////////////////////////////////////////////////
328/// We assume prepared statements work for all SQLite-versions.
329/// As we actually use the recommended sqlite3_prepare(),
330/// or, if possible, sqlite3_prepare_v2(),
331/// this already introduces the "compile time check".
332
334{
335 return kTRUE;
336}
337
338////////////////////////////////////////////////////////////////////////////////
339/// Produce TSQLiteStatement.
340
342{
343 if (!sql || !*sql) {
344 SetError(-1, "no query string specified", "Statement");
345 return nullptr;
346 }
347
348 if (!IsConnected()) {
349 Error("Statement", "not connected");
350 return nullptr;
351 }
352
353 sqlite3_stmt *preparedStmt = nullptr;
354
355 // -1 as we read until we encounter a \0.
356 // NULL because we do not check which char was read last.
357#if SQLITE_VERSION_NUMBER >= 3005000
358 int retVal = sqlite3_prepare_v2(fSQLite, sql, -1, &preparedStmt, NULL);
359#else
360 int retVal = sqlite3_prepare(fSQLite, sql, -1, &preparedStmt, NULL);
361#endif
362 if (retVal != SQLITE_OK) {
363 Error("Statement", "SQL Error: %d %s", retVal, sqlite3_errmsg(fSQLite));
364 return nullptr;
365 }
366
367 SQLite3_Stmt_t *stmt = new SQLite3_Stmt_t;
368 stmt->fConn = fSQLite;
369 stmt->fRes = preparedStmt;
370
371 return new TSQLiteStatement(stmt);
372}
373
374////////////////////////////////////////////////////////////////////////////////
375/// Return server info, must be deleted by user.
376
378{
379 if (!IsConnected()) {
380 Error("ServerInfo", "not connected");
381 return 0;
382 }
383
384 return fSrvInfo.Data();
385}
const Bool_t kFALSE
Definition RtypesCore.h:92
const Bool_t kTRUE
Definition RtypesCore.h:91
const char Option_t
Definition RtypesCore.h:66
#define ClassImp(name)
Definition Rtypes.h:364
#define SQLITE_OPEN_URI
char * Form(const char *fmt,...)
A doubly linked list.
Definition TList.h:44
virtual void Add(TObject *obj)
Definition TList.h:87
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:893
void MakeZombie()
Definition TObject.h:49
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.
TSQLResult * Query(const char *sql) final
Execute SQL command.
const char * ServerInfo() final
Return server info, must be deleted by user.
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 "START TRANSACTION" query to database return kTRUE, if successful
TSQLTableInfo * GetTableInfo(const char *tablename) final
Produces SQL table info.
Basic string class.
Definition TString.h:136
const char * Data() const
Definition TString.h:369
sqlite3_stmt * fRes