~ubuntu-branches/ubuntu/karmic/gears/karmic

« back to all changes in this revision

Viewing changes to gears/base/common/sqlite_wrapper.cc

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Lesicnik
  • Date: 2009-04-30 19:15:25 UTC
  • Revision ID: james.westby@ubuntu.com-20090430191525-0790sb5wzg8ou0xb
Tags: upstream-0.5.21.0~svn3334+dfsg
ImportĀ upstreamĀ versionĀ 0.5.21.0~svn3334+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright 2007, Google Inc.
 
2
//
 
3
// Redistribution and use in source and binary forms, with or without 
 
4
// modification, are permitted provided that the following conditions are met:
 
5
//
 
6
//  1. Redistributions of source code must retain the above copyright notice, 
 
7
//     this list of conditions and the following disclaimer.
 
8
//  2. Redistributions in binary form must reproduce the above copyright notice,
 
9
//     this list of conditions and the following disclaimer in the documentation
 
10
//     and/or other materials provided with the distribution.
 
11
//  3. Neither the name of Google Inc. nor the names of its contributors may be
 
12
//     used to endorse or promote products derived from this software without
 
13
//     specific prior written permission.
 
14
//
 
15
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 
16
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 
17
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 
18
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 
19
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
20
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 
21
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
22
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 
23
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
 
24
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
25
 
 
26
#include <vector>
 
27
#include "gears/base/common/file.h"
 
28
#include "gears/base/common/mutex.h"
 
29
#include "gears/base/common/paths.h"
 
30
#include "gears/base/common/sqlite_wrapper.h"
 
31
#include "gears/base/common/stopwatch.h"
 
32
#include "gears/base/common/string_utils.h"
 
33
#include "gears/base/common/thread_locals.h"
 
34
 
 
35
 
 
36
const char *SQLDatabase::kUnspecifiedTransactionLabel = "Unspecified";
 
37
 
 
38
// Returns a static string describing any SQLite status code.
 
39
// Based on SQLite's internal function sqlite3ErrStr().
 
40
const char16* SqliteRetvalAsString(int status) {
 
41
  const char16 *z;
 
42
  switch (status & 0xFF) {
 
43
    case SQLITE_ROW:
 
44
    case SQLITE_DONE:
 
45
    case SQLITE_OK:         z = STRING16(L"not an error");                           break;
 
46
    case SQLITE_ERROR:      z = STRING16(L"SQL logic error or missing database");    break;
 
47
    case SQLITE_PERM:       z = STRING16(L"access permission denied");               break;
 
48
    case SQLITE_ABORT:      z = STRING16(L"callback requested query abort");         break;
 
49
    case SQLITE_BUSY:       z = STRING16(L"database is locked");                     break;
 
50
    case SQLITE_LOCKED:     z = STRING16(L"database table is locked");               break;
 
51
    case SQLITE_NOMEM:      z = STRING16(L"out of memory");                          break;
 
52
    case SQLITE_READONLY:   z = STRING16(L"attempt to write a readonly database");   break;
 
53
    case SQLITE_INTERRUPT:  z = STRING16(L"interrupted");                            break;
 
54
    case SQLITE_IOERR:      z = STRING16(L"disk I/O error");                         break;
 
55
    case SQLITE_CORRUPT:    z = STRING16(L"database disk image is malformed");       break;
 
56
    case SQLITE_FULL:       z = STRING16(L"database or disk is full");               break;
 
57
    case SQLITE_CANTOPEN:   z = STRING16(L"unable to open database file");           break;
 
58
    case SQLITE_PROTOCOL:   z = STRING16(L"database locking protocol failure");      break;
 
59
    case SQLITE_EMPTY:      z = STRING16(L"table contains no data");                 break;
 
60
    case SQLITE_SCHEMA:     z = STRING16(L"database schema has changed");            break;
 
61
    case SQLITE_CONSTRAINT: z = STRING16(L"constraint failed");                      break;
 
62
    case SQLITE_MISMATCH:   z = STRING16(L"datatype mismatch");                      break;
 
63
    case SQLITE_MISUSE:     z = STRING16(L"library routine called out of sequence"); break;
 
64
    case SQLITE_NOLFS:      z = STRING16(L"kernel lacks large file support");        break;
 
65
    case SQLITE_AUTH:       z = STRING16(L"authorization denied");                   break;
 
66
    case SQLITE_FORMAT:     z = STRING16(L"auxiliary database format error");        break;
 
67
    case SQLITE_RANGE:      z = STRING16(L"bind or column index out of range");      break;
 
68
    case SQLITE_NOTADB:     z = STRING16(L"file is encrypted or is not a database"); break;
 
69
    default:                z = STRING16(L"unknown error");                          break;
 
70
  }
 
71
  return z;
 
72
}
 
73
 
 
74
 
 
75
void BuildSqliteErrorString(const char16 *summary, int sql_status, sqlite3 *db,
 
76
                            std::string16 *out) {
 
77
  out->clear();
 
78
  out->append(summary);
 
79
  out->append(STRING16(L" ERROR: "));
 
80
  out->append(SqliteRetvalAsString(sql_status));
 
81
  out->append(STRING16(L" DETAILS: "));
 
82
  out->append(STRING16(sqlite3_errmsg16(db)));
 
83
}
 
84
 
 
85
 
 
86
static void LogIfConspicuouslyLongTime(const char *format_str,
 
87
                                       int64 start_time,
 
88
                                       const char *label) {
 
89
  const int64 kConspicuoslyLongTimeMsec = 5 * 1000;
 
90
  int64 duration = GetCurrentTimeMillis() - start_time;
 
91
  if (duration > kConspicuoslyLongTimeMsec) {
 
92
    LOG((format_str, static_cast<int>(duration), label));
 
93
  }
 
94
}
 
95
 
 
96
//------------------------------------------------------------------------------
 
97
// Constructor and Destructor
 
98
//------------------------------------------------------------------------------
 
99
 
 
100
SQLDatabase::SQLDatabase() : 
 
101
    db_(NULL), transaction_count_(0), needs_rollback_(false), 
 
102
    transaction_start_time_(0), opt_transaction_mutex_(NULL),
 
103
    transaction_listener_(NULL) {
 
104
}
 
105
 
 
106
 
 
107
SQLDatabase::~SQLDatabase() {
 
108
  Close();
 
109
}
 
110
 
 
111
//------------------------------------------------------------------------------
 
112
// Open
 
113
//------------------------------------------------------------------------------
 
114
bool SQLDatabase::Open(const char16 *name) {
 
115
  ASSERT_SINGLE_THREAD();
 
116
 
 
117
  // When parameter binding multiple parameters, we frequently use a scheme
 
118
  // of OR'ing return values together for testing for an error once after
 
119
  // all rv |= bind_foo() assignments have been made. This relies on
 
120
  // SQLITE_OK being 0.
 
121
  assert(SQLITE_OK == 0);
 
122
 
 
123
  // For testing purposes, we've seperated opening and configuring the
 
124
  // sqlite3 connection.
 
125
  if (!OpenConnection(name)) {
 
126
    return false;
 
127
  }
 
128
 
 
129
  if (!ConfigureConnection()) {
 
130
    sqlite3_close(db_);
 
131
    db_ = NULL;
 
132
    return false;
 
133
  }
 
134
 
 
135
  return true; 
 
136
}
 
137
 
 
138
bool SQLDatabase::OpenConnection(const char16 *name) {
 
139
  // Nobody should be calling Open() twice.
 
140
  assert(!db_);
 
141
  if (db_) {
 
142
    LOG(("SQLDatabase: already open\n"));
 
143
    return false;
 
144
  }
 
145
 
 
146
  transaction_count_ = 0;
 
147
  needs_rollback_ = false;
 
148
 
 
149
  std::string16 path;
 
150
  if (!GetFullDatabaseFilePath(name, &path)) {
 
151
    return false;
 
152
  }
 
153
 
 
154
  if (SQLITE_OK != sqlite3_open16(path.c_str(), &db_)) {
 
155
    // sqlite3_close() should be called after sqlite3_open() failures.
 
156
    // The DB handle may be valid or NULL, sqlite3_close() handles
 
157
    // either.
 
158
    sqlite3_close(db_);
 
159
    db_ = NULL;
 
160
    return false;
 
161
  }
 
162
 
 
163
  return true;
 
164
}
 
165
 
 
166
bool SQLDatabase::ConfigureConnection() {
 
167
  assert(db_);
 
168
  // Set the busy timeout value before executing any SQL statements.
 
169
  // With the timeout value set, SQLite will wait and retry if another
 
170
  // thread has the database locked rather than immediately fail with an
 
171
  // SQLITE_BUSY error.
 
172
  if (SQLITE_OK != sqlite3_busy_timeout(db_, kBusyTimeout)) {
 
173
    LOG(("SQLDatabase: Could not set busy timeout: %d\n",
 
174
         sqlite3_errcode(db_)));
 
175
    return false;
 
176
  }
 
177
 
 
178
  // Turn off flushing writes thru to disk, significantly faster (2x)
 
179
  if (SQLITE_OK != 
 
180
      sqlite3_exec(db_, "PRAGMA synchronous = OFF" , NULL, NULL, NULL)) {
 
181
    LOG(("SQLDatabase: Could not set PRAGMA synchronous: %d\n", 
 
182
         sqlite3_errcode(db_)));
 
183
    return false;
 
184
  }
 
185
 
 
186
  // Use UTF8, significantly smaller
 
187
  if (SQLITE_OK != 
 
188
      sqlite3_exec(db_, "PRAGMA encoding = \"UTF-8\"", NULL, NULL, NULL)) {
 
189
    LOG(("SQLDatabase: Could not set PRAGMA encoding: %d\n", 
 
190
         sqlite3_errcode(db_)));
 
191
    return false;
 
192
  }
 
193
 
 
194
  return true;
 
195
}
 
196
 
 
197
 
 
198
//------------------------------------------------------------------------------
 
199
// Close
 
200
//------------------------------------------------------------------------------
 
201
void SQLDatabase::Close() {
 
202
  if (db_) {
 
203
    sqlite3_close(db_);
 
204
    db_ = NULL;
 
205
    if (IsInTransaction() && opt_transaction_mutex_) {
 
206
      opt_transaction_mutex_->Unlock();
 
207
    }
 
208
  }  
 
209
}
 
210
 
 
211
 
 
212
//------------------------------------------------------------------------------
 
213
// IsOpen
 
214
//------------------------------------------------------------------------------
 
215
bool SQLDatabase::IsOpen() {
 
216
  ASSERT_SINGLE_THREAD();
 
217
  return db_ != NULL;
 
218
}
 
219
 
 
220
 
 
221
//------------------------------------------------------------------------------
 
222
// BeginTransaction
 
223
//------------------------------------------------------------------------------
 
224
bool SQLDatabase::BeginTransaction(const char *log_label) {
 
225
  ASSERT_SINGLE_THREAD();
 
226
  assert(db_);
 
227
  if (!db_) {
 
228
    return false;
 
229
  }
 
230
 
 
231
  if (!log_label)
 
232
    log_label = kUnspecifiedTransactionLabel;
 
233
 
 
234
  // EndTransaction should have been watching out for us going negative.
 
235
  assert(transaction_count_ >= 0);
 
236
 
 
237
  if (transaction_count_ > 0) {
 
238
    if (needs_rollback_) {
 
239
      LOG(("SQLDatabase: Cannot begin transaction for %s"
 
240
               " - already rolled back\n",
 
241
           log_label));
 
242
      return false;
 
243
    } else {
 
244
      ++transaction_count_;
 
245
      return true;
 
246
    }
 
247
  }
 
248
 
 
249
  LOG(("SQLDatabase: BeginTransaction for %s\n", log_label));
 
250
  transaction_start_time_ = GetCurrentTimeMillis();
 
251
 
 
252
  if (opt_transaction_mutex_) {
 
253
    opt_transaction_mutex_->Lock();
 
254
  }
 
255
 
 
256
  // We always use BEGIN IMMEDIATE for now but this could be parameterized in
 
257
  // the future if necessary.
 
258
  if (SQLITE_OK != sqlite3_exec(db_, "BEGIN IMMEDIATE", NULL, NULL, NULL)) {
 
259
    if (opt_transaction_mutex_) {
 
260
      opt_transaction_mutex_->Unlock();
 
261
    }
 
262
    LOG(("SQLDatabase: Cannot exceute BEGIN IMMEDIATE: %d for %s\n", 
 
263
         sqlite3_errcode(db_),
 
264
         log_label));
 
265
    return false;
 
266
  }
 
267
 
 
268
  LogIfConspicuouslyLongTime(
 
269
      "SQLDatabase: Warning, BEGIN IMMEDIATE took %d ms for %s\n",
 
270
      transaction_start_time_, log_label);
 
271
 
 
272
  needs_rollback_ = false;
 
273
  ++transaction_count_;
 
274
 
 
275
  if (transaction_listener_) {
 
276
    transaction_listener_->OnBegin();
 
277
  }
 
278
 
 
279
  return true;
 
280
}
 
281
 
 
282
 
 
283
//------------------------------------------------------------------------------
 
284
// RollbackTransaction
 
285
//------------------------------------------------------------------------------
 
286
void SQLDatabase::RollbackTransaction(const char *log_label) {
 
287
  ASSERT_SINGLE_THREAD();
 
288
  needs_rollback_ = true;
 
289
  EndTransaction(log_label);
 
290
}
 
291
 
 
292
 
 
293
//------------------------------------------------------------------------------
 
294
// CommitTransaction
 
295
//------------------------------------------------------------------------------
 
296
bool SQLDatabase::CommitTransaction(const char *log_label) {
 
297
  ASSERT_SINGLE_THREAD();
 
298
 
 
299
  if (!EndTransaction(log_label)) {
 
300
    return false;
 
301
  }
 
302
 
 
303
  return !needs_rollback_;
 
304
}
 
305
 
 
306
 
 
307
//------------------------------------------------------------------------------
 
308
// EndTransaction
 
309
//------------------------------------------------------------------------------
 
310
bool SQLDatabase::EndTransaction(const char *log_label) {
 
311
  ASSERT_SINGLE_THREAD();
 
312
 
 
313
  if (!log_label)
 
314
    log_label = kUnspecifiedTransactionLabel;
 
315
 
 
316
  if (0 == transaction_count_) {
 
317
    LOG(("SQLDatabase: unbalanced transaction - %s\n", log_label));
 
318
    assert(false);
 
319
    return false;
 
320
  }
 
321
 
 
322
  // Always decrement. If Commit() fails we will Rollback(), which cannot fail.
 
323
  --transaction_count_;
 
324
 
 
325
  assert(db_);
 
326
  if (!db_) {
 
327
    return false;
 
328
  }
 
329
 
 
330
  if (transaction_count_ > 0) {
 
331
    // This is not the top tx, nothing to do
 
332
    return true;
 
333
  }
 
334
 
 
335
  LOG(("SQLDatabase: EndTransaction for %s\n", log_label));
 
336
 
 
337
  // OK, we are closing the last transaction, commit provided rollback has
 
338
  // not been called.
 
339
  if (!needs_rollback_) {
 
340
    if (SQLITE_OK == sqlite3_exec(db_, "COMMIT", NULL, NULL, NULL)) {
 
341
      if (opt_transaction_mutex_) {
 
342
        opt_transaction_mutex_->Unlock();
 
343
      }
 
344
      LogIfConspicuouslyLongTime(
 
345
          "SQLDatabase: Committed transaction was open for %d ms for %s\n",
 
346
          transaction_start_time_, log_label);
 
347
 
 
348
      if (transaction_listener_) {
 
349
        transaction_listener_->OnCommit();
 
350
      }
 
351
      return true;
 
352
    }
 
353
 
 
354
    LOG(("SQLDatabase: Could not execute COMMIT: %d\n",
 
355
         sqlite3_errcode(db_)));
 
356
 
 
357
    // Since commit did not succeed, we should rollback. For most types of
 
358
    // errors, sqlite has already rolled back at this point. But for
 
359
    // SQLITE_BUSY, it won't have, and we want to treat that as an error.
 
360
  }
 
361
 
 
362
  // Rollback is necessary.
 
363
  // TODO(aa): What, if any, are the cases that rollback can fail. Should we do
 
364
  // anything about them?
 
365
  sqlite3_exec(db_, "ROLLBACK", NULL, NULL, NULL);
 
366
  if (opt_transaction_mutex_) {
 
367
    opt_transaction_mutex_->Unlock();
 
368
  }
 
369
  LogIfConspicuouslyLongTime(
 
370
      "SQLDatabase: Rolled back transaction was open for %d ms for %s\n",
 
371
      transaction_start_time_, log_label);
 
372
 
 
373
  if (transaction_listener_) {
 
374
    transaction_listener_->OnRollback();
 
375
  }
 
376
 
 
377
  LOG(("SQLDatabase: Rolled back transaction for %s\n", log_label));
 
378
  return false;
 
379
}
 
380
 
 
381
 
 
382
//------------------------------------------------------------------------------
 
383
// DropAllObjects
 
384
//------------------------------------------------------------------------------
 
385
bool SQLDatabase::DropAllObjects() {
 
386
  // It appears that when you drop a table, it's associated indicies and
 
387
  // triggers also get dropped. However, shess cautions that there have been
 
388
  // bugs where virtual tables could not be dropped after the tables they
 
389
  // depedended upon had been dropped. This means that if we ever start using
 
390
  // virtual tables with this class, we may need to revisit this
 
391
  // implementation and find a way to distinguish virtual tables from regular
 
392
  // ones and drop those first.
 
393
  SQLTransaction tx(this, "SQLDatabase::DropAllObjects");
 
394
  if (!tx.Begin()) {
 
395
    return false;
 
396
  }
 
397
 
 
398
  // Find all the tables and gather them into a list
 
399
  SQLStatement stmt;
 
400
  const char16 *select_sql = 
 
401
    STRING16(L"SELECT name FROM sqlite_master WHERE type = 'table'");
 
402
  if (SQLITE_OK != stmt.prepare16(this, select_sql)) {
 
403
    LOG(("SQLDatabase::DropAllObjects - error preparing select: %d\n",
 
404
         sqlite3_errcode(db_)));
 
405
    return false;
 
406
  }
 
407
 
 
408
  std::vector<std::string16> table_names;
 
409
  int rv = stmt.step();
 
410
  while (SQLITE_ROW == rv) {
 
411
    table_names.push_back(std::string16(stmt.column_text16_safe(0)));
 
412
    rv = stmt.step();
 
413
  }
 
414
 
 
415
  if (SQLITE_DONE != rv) {
 
416
    LOG(("SQLDatabase::DropAllObjects - error iterating objects: %d\n",
 
417
         sqlite3_errcode(db_)));
 
418
    return false;
 
419
  }
 
420
 
 
421
  // Now iterate the list and drop all the tables we found
 
422
  for (std::vector<std::string16>::iterator iter = table_names.begin();
 
423
       iter != table_names.end(); ++iter) {
 
424
    SQLStatement drop_stmt;
 
425
    std::string16 drop_sql(STRING16(L"DROP TABLE "));
 
426
    drop_sql += (*iter);
 
427
    if (SQLITE_OK != drop_stmt.prepare16(this, drop_sql.c_str())) {
 
428
      // Some tables internal to sqlite may not be dropped, for example
 
429
      // sqlite_sequence. We ignore this error.
 
430
      if (StartsWith(*iter, std::string16(STRING16(L"sqlite_sequence"))))
 
431
        continue;
 
432
      return false;     
 
433
    }
 
434
 
 
435
    if (SQLITE_DONE != drop_stmt.step()) {
 
436
      LOG(("SQLDatabase::DropAllObjects - error dropping table: %d\n",
 
437
           sqlite3_errcode(db_)));
 
438
      return false;
 
439
    }
 
440
  }
 
441
 
 
442
  if (!tx.Commit()) {
 
443
    return false;
 
444
  }
 
445
 
 
446
  return true;
 
447
}
 
448
 
 
449
 
 
450
//------------------------------------------------------------------------------
 
451
// GetDBHandle
 
452
//------------------------------------------------------------------------------
 
453
sqlite3 *SQLDatabase::GetDBHandle() {
 
454
  ASSERT_SINGLE_THREAD();
 
455
 
 
456
  return db_;
 
457
}
 
458
 
 
459
 
 
460
//------------------------------------------------------------------------------
 
461
// SetTransactionListener
 
462
//------------------------------------------------------------------------------
 
463
void SQLDatabase::SetTransactionListener(SQLTransactionListener *listener) {
 
464
  ASSERT_SINGLE_THREAD();
 
465
 
 
466
  transaction_listener_ = listener;
 
467
}
 
468
 
 
469
 
 
470
//------------------------------------------------------------------------------
 
471
// GetFullDatabaseFilePath
 
472
//------------------------------------------------------------------------------
 
473
// static
 
474
bool SQLDatabase::GetFullDatabaseFilePath(const char16 *filename, 
 
475
                                          std::string16 *path) {
 
476
  if (!GetBaseDataDirectory(path)) {
 
477
    return false;
 
478
  }
 
479
  if (!File::RecursivelyCreateDir(path->c_str())) {
 
480
    return false;
 
481
  }
 
482
  (*path) += kPathSeparator;
 
483
  (*path) += filename;
 
484
  return true;
 
485
}