GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/sql.h Lines: 80 84 95.2 %
Date: 2019-02-03 02:48:13 Branches: 14 18 77.8 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM file system.
3
 */
4
5
#ifndef CVMFS_SQL_H_
6
#define CVMFS_SQL_H_
7
8
#include <cassert>
9
#include <string>
10
11
#include "duplex_sqlite3.h"
12
#include "util/file_guard.h"
13
#include "util/pointer.h"
14
15
namespace sqlite {
16
17
struct MemStatistics {
18
1
  MemStatistics()
19
    : lookaside_slots_used(-1)
20
    , lookaside_slots_max(-1)
21
    , lookaside_hit(-1)
22
    , lookaside_miss_size(-1)
23
    , lookaside_miss_full(-1)
24
    , page_cache_used(-1)
25
    , page_cache_hit(-1)
26
    , page_cache_miss(-1)
27
    , schema_used(-1)
28
1
    , stmt_used(-1)
29
1
  { }
30
  int lookaside_slots_used;
31
  int lookaside_slots_max;
32
  int lookaside_hit;
33
  int lookaside_miss_size;
34
  int lookaside_miss_full;
35
  int page_cache_used;   ///< Bytes used for caching pages
36
  int page_cache_hit;
37
  int page_cache_miss;
38
  int schema_used;  ///< Bytes used to store db schema
39
  int stmt_used;  ///< Bytes used for prepared statmements (lookaside + heap)
40
};
41
42
class Sql;
43
44
/**
45
 * Encapsulates an SQlite connection.
46
 *
47
 * This is an abstract base class for different SQLite database flavours used
48
 * throughout CernVM-FS. It provides a general interface for creating, opening,
49
 * compacting and migrating an SQLite database.
50
 * Furthermore it manages a `properties` table in each database, to store simple
51
 * key-value style information in a common fashion. For that, it offers the
52
 * templated methods SetProperty(), GetProperty<>() and HasProperty() that take
53
 * all common data types and persist it in the database.
54
 *
55
 * By default Database<> objects do not take ownership of the underlying SQLite
56
 * database file and hence do not unlink it on database closure. If the using
57
 * code calls Database<>::TakeFileOwnership() the SQLite file will be unlinked
58
 * in the destructor of the Database<> object.
59
 *
60
 * Note: This implements a Curiously Recurring Template Pattern in order to
61
 *       implement Database::Create and Database::Open as a static polymorphism
62
 *
63
 *  The following methods need to be implemented by each subclass:
64
 *  (Database<> assumes 'true' as a return value on success)
65
 *
66
 *  -> bool CreateEmptyDatabase()
67
 *              creates all necessary SQLite tables for the concrete Database
68
 *              implementation. Furthermore it can insert default data into the
69
 *              newly created database tables.
70
 *  -> bool CheckSchemaCompatibility()
71
 *              checks a database for compatibility directly after opening it.
72
 *              Database<> provides schema_version() and schema_revision() to
73
 *              access the compatibility stored in the `properties` table
74
 *  -> bool LiveSchemaUpgradeIfNecessary()
75
 *              this allows for on-the-fly schema updates and is always called
76
 *              when a database is opened read/write. It assumes 'true' both on
77
 *              successful migration and if no migration was necessary
78
 *  -> bool CompactDatabase()
79
 *              here implementation specific cleanup actions can take place on
80
 *              databases opened as read/write. It is invoked by the `Vacuum()`
81
 *              method, that can be used by higher level user code
82
 *
83
 *  Furthermore Database<> expects two static constants to be defined:
84
 *
85
 *  -> kLatestSchema  - the newest schema version generated by invoking
86
 *                      DerivedT::CreateEmptyDatabase()
87
 *  -> kLatestSchemaRevision - same as kLatestSchema, however different schema
88
 *                             revisions are supposed to be backward compatible
89
 *                             or on-the-fly updateable by
90
 *                             DerivedT::LiveSchemaUpgradeIfNecessary()
91
 *
92
 * @param DerivedT  the name of the inheriting Database implementation class
93
 *                  (Curiously Recurring Template Pattern)
94
 *
95
 * TODO(rmeusel): C++11 Move Constructors to allow for stack allocated databases
96
 */
97
template <class DerivedT>
98
368
class Database : SingleCopy {
99
 public:
100
  enum OpenMode {
101
    kOpenReadOnly,
102
    kOpenReadWrite,
103
  };
104
105
  static const float kSchemaEpsilon;  // floats get imprecise in SQlite
106
107
  /**
108
   * Creates a new database file of the type implemented by DerivedT. During the
109
   * invocation of this static method DerivedT::CreateEmptyDatabase() is called.
110
   *
111
   * @param filename  the file location of the newly created database
112
   *                  (file does not need to exist)
113
   * @return          an empty database of type DerivedT (or NULL on failure)
114
   */
115
  static DerivedT* Create(const std::string  &filename);
116
117
  /**
118
   * Opens a database file and assumes it to be of type DerivedT. This method
119
   * will call DerivedT::CheckSchemaCompatibility() to figure out readability of
120
   * the contained schema revision. Furthermore, if the database was opened in
121
   * read/write mode, it calls DerivedT::LiveSchemaUpgradeIfNecessary() to allow
122
   * for on-the-fly schema upgrades of the underlying database file.
123
   *
124
   * @param filename   path to the SQLite file to be opened as DerivedT
125
   * @param open_mode  kOpenReadOnly or kOpenReadWrite open modes
126
   * @return           a database of type DerivedT (or NULL on failure)
127
   */
128
  static DerivedT* Open(const std::string  &filename,
129
                        const OpenMode      open_mode);
130
131
1704
  bool IsEqualSchema(const float value, const float compare) const {
132
    return (value > compare - kSchemaEpsilon &&
133

1704
            value < compare + kSchemaEpsilon);
134
  }
135
136
  bool BeginTransaction() const;
137
  bool CommitTransaction() const;
138
139
  template <typename T>
140
  T GetProperty(const std::string &key) const;
141
  template <typename T>
142
  T GetPropertyDefault(const std::string &key, const T default_value) const;
143
  template <typename T>
144
  bool SetProperty(const std::string &key, const T value);
145
  bool HasProperty(const std::string &key) const;
146
147
5616
  sqlite3*            sqlite_db()       const { return database_.database();  }
148
1240
  const std::string&  filename()        const { return database_.filename();  }
149
2794
  float               schema_version()  const { return schema_version_;       }
150
3282
  unsigned            schema_revision() const { return schema_revision_;      }
151
835
  bool                read_write()      const { return read_write_;           }
152
153
  /**
154
   * Provides the number of rows modified by INSERT, UPDATE or DELETE statements
155
   * that have been run against this database since it was opened.
156
   * @return  number of rows modified by all executed manipulating statements
157
   */
158
  unsigned GetModifiedRowCount() const;
159
160
  /**
161
   * Figures out the ratio of free SQLite memory pages in the SQLite database
162
   * file. A high ratio can be an indication of a necessary call to Vacuum().
163
   * Note: This is not done automatically and the decision is left to the using
164
   *       code!
165
   * @return  the free-page ratio in the opened database file (free pages/pages)
166
   */
167
  double GetFreePageRatio() const;
168
169
  /**
170
   * Retrieves the per-connection memory statistics from SQlite
171
   */
172
  void GetMemStatistics(MemStatistics *stats) const;
173
174
  /**
175
   * Performs a VACUUM call on the opened database file to compacts the database.
176
   * As a first step it runs DerivedT::CompactDatabase() to allow for implement-
177
   * ation dependent cleanup actions. Vacuum() assumes that the SQLite database
178
   * was opened in read/write mode.
179
   * @return  true on success
180
   */
181
  bool Vacuum() const;
182
183
  /**
184
   * Prints the given error message, together with the last encountered SQLite
185
   * error of this database.
186
   * @param error_msg  an error message to be printed along with the SQL error
187
   */
188
  void PrintSqlError(const std::string &error_msg);
189
190
  /**
191
   * Returns the english language error description of the last error
192
   * happened in the context of the encapsulated sqlite3 database object.
193
   * Note: In a multithreaded context it might be unpredictable which
194
   *       the actual last error is.
195
   * @return   english language error description of last error
196
   */
197
  std::string GetLastErrorMsg() const;
198
199
200
  /**
201
   * Transfers the ownership of the SQLite database file to the Database<> ob-
202
   * ject. Hence, it will automatically unlink the file, once the Database<>
203
   * object goes out of scope or is deleted.
204
   */
205
  void TakeFileOwnership();
206
207
  /**
208
   * Resigns from the ownership of the SQLite database file underlying this
209
   * Database<> object. After calling this the using code is responsible of
210
   * managing the database file.
211
   */
212
  void DropFileOwnership();
213
214
  /**
215
   * Check if the SQLite database file is managed by the Database<> object
216
   * Note: unmanaged means, that the using code needs to take care of the file
217
   *       management (i.e. delete the file after usage)
218
   *
219
   * @return  false if file is unmanaged
220
   */
221
27
  bool OwnsFile() const { return database_.OwnsFile(); }
222
223
 protected:
224
  /**
225
   * Private constructor! Use the factory methods DerivedT::Create() or
226
   * DerivedT::Open() to instantiate a database object of type DerivedT.
227
   */
228
  Database(const std::string  &filename,
229
           const OpenMode      open_mode);
230
231
  bool Initialize();
232
233
  bool CreatePropertiesTable();
234
  bool PrepareCommonQueries();
235
236
  bool OpenDatabase(const int sqlite_open_flags);
237
  bool Configure();
238
  bool FileReadAhead();
239
240
  void ReadSchemaRevision();
241
  bool StoreSchemaRevision();
242
243
197
  void set_schema_version(const float ver)     { schema_version_  = ver; }
244
213
  void set_schema_revision(const unsigned rev) { schema_revision_ = rev; }
245
246
 private:
247
  /**
248
   * This wraps the opaque SQLite database object along with a file unlink guard
249
   * to control the life time of the database connection and the database file
250
   * in an RAII fashion.
251
   */
252
  struct DatabaseRaiiWrapper {
253
369
    DatabaseRaiiWrapper(const std::string   &filename,
254
                        Database<DerivedT>  *delegate)
255
      : sqlite_db(NULL)
256
      , lookaside_buffer(NULL)
257
      , db_file_guard(filename, UnlinkGuard::kDisabled)
258
369
      , delegate_(delegate) {}
259
    ~DatabaseRaiiWrapper();
260
261
5616
    sqlite3*           database() const { return sqlite_db;            }
262
1665
    const std::string& filename() const { return db_file_guard.path(); }
263
264
    bool Close();
265
266
53
    void TakeFileOwnership() { db_file_guard.Enable();           }
267
4
    void DropFileOwnership() { db_file_guard.Disable();          }
268
27
    bool OwnsFile() const    { return db_file_guard.IsEnabled(); }
269
270
    sqlite3             *sqlite_db;
271
    void                *lookaside_buffer;
272
    UnlinkGuard          db_file_guard;
273
    Database<DerivedT>  *delegate_;
274
  };
275
276
  static const std::string kSchemaVersionKey;
277
  static const std::string kSchemaRevisionKey;
278
279
  DatabaseRaiiWrapper database_;
280
281
  const bool          read_write_;
282
  float               schema_version_;
283
  unsigned            schema_revision_;
284
285
  UniquePtr<Sql>      begin_transaction_;
286
  UniquePtr<Sql>      commit_transaction_;
287
288
  UniquePtr<Sql>      has_property_;
289
  UniquePtr<Sql>      set_property_;
290
  UniquePtr<Sql>      get_property_;
291
};
292
293
294
//
295
// # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
296
//
297
298
299
/**
300
 * Base class for all SQL statement classes.  It wraps a single SQL statement
301
 * and all neccessary calls of the sqlite3 API to deal with this statement.
302
 *
303
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
304
 * NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE  *
305
 * NOTE   This base class implements a lazy initialization of the SQLite       *
306
 * NOTE   prepared statement. Therefore it is strongly discouraged to use      *
307
 * NOTE   any sqlite3_***() functions directly in the subclasses. Instead      *
308
 * NOTE   one must wrap them in this base class and implement the lazy         *
309
 * NOTE   initialization scheme as seen below.                                 *
310
 * NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE  *
311
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
312
 *
313
 * Derived classes can decide if their statement should be prepared immediately
314
 * or on first use (aka lazily). The derived constructor must call Sql::Init()
315
 * or Sql::DeferredInit() accordingly.
316
 *
317
 * Sql objects created via the public constructor rather than by the constructor
318
 * of a derived class are prepared immediately by default.
319
 */
320
class Sql {
321
 public:
322
  /**
323
   * Basic constructor to use this class for a specific statement.
324
   * @param database the database to use the query on
325
   * @param statement the statement to prepare
326
   */
327
  Sql(sqlite3 *sqlite_db, const std::string &statement);
328
  virtual ~Sql();
329
330
  bool Execute();
331
  bool FetchRow();
332
  std::string DebugResultTable();
333
  bool Reset();
334
6
  inline int GetLastError() const { return last_error_code_; }
335
336
  /**
337
   * Returns the english language error description of the last error
338
   * happened in the context of the sqlite3 database object this statement is
339
   * registered to.
340
   * Note: In a multithreaded context it might be unpredictable which
341
   *       the actual last error is.
342
   * @return   english language error description of last error
343
   */
344
  std::string GetLastErrorMsg() const;
345
346
91
  bool BindBlob(const int index, const void* value, const int size) {
347
91
    LazyInit();
348
    last_error_code_ = sqlite3_bind_blob(statement_, index, value, size,
349
91
                                         SQLITE_STATIC);
350
91
    return Successful();
351
  }
352
  bool BindBlobTransient(const int index, const void* value, const int size) {
353
    LazyInit();
354
    last_error_code_ = sqlite3_bind_blob(statement_, index, value, size,
355
                                         SQLITE_TRANSIENT);
356
    return Successful();
357
  }
358
214
  bool BindDouble(const int index, const double value) {
359
214
    LazyInit();
360
214
    last_error_code_ = sqlite3_bind_double(statement_, index, value);
361
214
    return Successful();
362
  }
363
546
  bool BindInt(const int index, const int value) {
364
546
    LazyInit();
365
546
    last_error_code_ = sqlite3_bind_int(statement_, index, value);
366
546
    return Successful();
367
  }
368
22587
  bool BindInt64(const int index, const sqlite3_int64 value) {
369
22587
    LazyInit();
370
22587
    last_error_code_ = sqlite3_bind_int64(statement_, index, value);
371
22587
    return Successful();
372
  }
373
366
  bool BindNull(const int index) {
374
366
    LazyInit();
375
366
    last_error_code_ = sqlite3_bind_null(statement_, index);
376
366
    return Successful();
377
  }
378
154532
  bool BindTextTransient(const int index, const std::string &value) {
379
154532
    return BindTextTransient(index, value.data(), value.length());
380
  }
381
154536
  bool BindTextTransient(const int index, const char *value, const int size) {
382
154536
    return BindText(index, value, size, SQLITE_TRANSIENT);
383
  }
384
170110
  bool BindText(const int index, const std::string &value) {
385
170110
    return BindText(index, value.data(), value.length(), SQLITE_STATIC);
386
  }
387
325204
  bool BindText(const int   index,
388
                const char* value,
389
                const int   size,
390
                void(*dtor)(void*) = SQLITE_STATIC) {
391
325204
    LazyInit();
392
325204
    last_error_code_ = sqlite3_bind_text(statement_, index, value, size, dtor);
393
325204
    return Successful();
394
  }
395
396
  /**
397
   * Figures out the type to be bound by template parameter deduction
398
   * NOTE: For strings or char* buffers this is suboptimal, since it needs to
399
   *       assume that the provided buffer is transient and copy it to be sure.
400
   *       Furthermore, for char* buffers we need to assume a null-terminated
401
   *       C-like string to obtain its length using strlen().
402
   */
403
  template <typename T>
404
  inline bool Bind(const int index, const T value);
405
406
407
32
  int RetrieveType(const int idx_column) const {
408
32
    return sqlite3_column_type(statement_, idx_column);
409
  }
410
411
  /**
412
   * Determines the number of bytes necessary to store the column's data as a
413
   * string. This might involve type conversions and depends on which other
414
   * RetrieveXXX methods were called on the same column index before!
415
   *
416
   * See SQLite documentation for sqlite_column_bytes() for details:
417
   *   https://www.sqlite.org/c3ref/column_blob.html
418
   */
419
212
  int RetrieveBytes(const int idx_column) const {
420
212
    return sqlite3_column_bytes(statement_, idx_column);
421
  }
422
213
  const void *RetrieveBlob(const int idx_column) const {
423
213
    return sqlite3_column_blob(statement_, idx_column);
424
  }
425
193
  double RetrieveDouble(const int idx_column) const {
426
193
    return sqlite3_column_double(statement_, idx_column);
427
  }
428
643
  int RetrieveInt(const int idx_column) const {
429
643
    return sqlite3_column_int(statement_, idx_column);
430
  }
431
10366
  sqlite3_int64 RetrieveInt64(const int idx_column) const {
432
10366
    return sqlite3_column_int64(statement_, idx_column);
433
  }
434
7620
  const unsigned char *RetrieveText(const int idx_column) const {
435
7620
    return sqlite3_column_text(statement_, idx_column);
436
  }
437
7176
  std::string RetrieveString(const int idx_column) const {
438
7176
    return reinterpret_cast<const char*>(RetrieveText(idx_column));
439
  }
440
  template <typename T>
441
  inline T Retrieve(const int index);
442
443
 protected:
444
3801
  Sql()
445
    : database_(NULL)
446
    , statement_(NULL)
447
    , query_string_(NULL)
448
3801
    , last_error_code_(0) { }
449
450
516404
  bool IsInitialized() const { return statement_ != NULL; }
451
452
  /**
453
   * Initializes the prepared statement immediately.
454
   *
455
   * @param database   the sqlite database pointer to be query against
456
   * @param statement  the query string to be prepared for execution
457
   * @return           true on successful statement preparation
458
   */
459
  bool Init(const sqlite3 *database, const std::string &statement);
460
461
  /**
462
   * Defers the initialization of the prepared statement to the first usage to
463
   * safe memory and CPU cycles for statements that are defined but never used.
464
   * Typically this method is used in constructors of derived classes.
465
   *
466
   * @param database   the sqlite database pointer to be query against
467
   * @param statement  the query string to be prepared for execution
468
   */
469
  void DeferredInit(const sqlite3 *database, const char *statement);
470
471
  /**
472
   * Checks the last action for success
473
   * @return true if last action succeeded otherwise false
474
   */
475
840679
  inline bool Successful() const {
476
    return SQLITE_OK   == last_error_code_ ||
477
           SQLITE_ROW  == last_error_code_ ||
478

840679
           SQLITE_DONE == last_error_code_;
479
  }
480
481
 private:
482
  bool Init(const char *statement);
483
516404
  void LazyInit() {
484
516404
    if (!IsInitialized()) {
485
557
      assert(NULL != database_);
486
557
      assert(NULL != query_string_);
487
557
      const bool success = Init(query_string_);
488
557
      assert(success);
489
    }
490
516404
  }
491
492
  sqlite3       *database_;
493
  sqlite3_stmt  *statement_;
494
  const char    *query_string_;
495
  int            last_error_code_;
496
};
497
498
}  // namespace sqlite
499
500
#include "sql_impl.h"
501
502
#endif  // CVMFS_SQL_H_