| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 /* |  | 
| 2  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. |  | 
| 3  * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com) |  | 
| 4  * |  | 
| 5  * Redistribution and use in source and binary forms, with or without |  | 
| 6  * modification, are permitted provided that the following conditions |  | 
| 7  * are met: |  | 
| 8  * 1. Redistributions of source code must retain the above copyright |  | 
| 9  *    notice, this list of conditions and the following disclaimer. |  | 
| 10  * 2. Redistributions in binary form must reproduce the above copyright |  | 
| 11  *    notice, this list of conditions and the following disclaimer in the |  | 
| 12  *    documentation and/or other materials provided with the distribution. |  | 
| 13  * |  | 
| 14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |  | 
| 15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |  | 
| 16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |  | 
| 17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR |  | 
| 18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |  | 
| 19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |  | 
| 20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |  | 
| 21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |  | 
| 22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |  | 
| 23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |  | 
| 24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | 
| 25  */ |  | 
| 26 |  | 
| 27 #include "config.h" |  | 
| 28 #include "core/platform/sql/SQLiteDatabase.h" |  | 
| 29 |  | 
| 30 #include <sqlite3.h> |  | 
| 31 #include "platform/Logging.h" |  | 
| 32 #include "core/platform/sql/SQLiteFileSystem.h" |  | 
| 33 #include "core/platform/sql/SQLiteStatement.h" |  | 
| 34 #include "modules/webdatabase/DatabaseAuthorizer.h" |  | 
| 35 #include "wtf/text/CString.h" |  | 
| 36 #include "wtf/text/WTFString.h" |  | 
| 37 #include "wtf/Threading.h" |  | 
| 38 |  | 
| 39 namespace WebCore { |  | 
| 40 |  | 
| 41 const int SQLResultDone = SQLITE_DONE; |  | 
| 42 const int SQLResultError = SQLITE_ERROR; |  | 
| 43 const int SQLResultOk = SQLITE_OK; |  | 
| 44 const int SQLResultRow = SQLITE_ROW; |  | 
| 45 const int SQLResultSchema = SQLITE_SCHEMA; |  | 
| 46 const int SQLResultFull = SQLITE_FULL; |  | 
| 47 const int SQLResultInterrupt = SQLITE_INTERRUPT; |  | 
| 48 const int SQLResultConstraint = SQLITE_CONSTRAINT; |  | 
| 49 |  | 
| 50 static const char notOpenErrorMessage[] = "database is not open"; |  | 
| 51 |  | 
| 52 SQLiteDatabase::SQLiteDatabase() |  | 
| 53     : m_db(0) |  | 
| 54     , m_pageSize(-1) |  | 
| 55     , m_transactionInProgress(false) |  | 
| 56     , m_sharable(false) |  | 
| 57     , m_openingThread(0) |  | 
| 58     , m_interrupted(false) |  | 
| 59     , m_openError(SQLITE_ERROR) |  | 
| 60     , m_openErrorMessage() |  | 
| 61     , m_lastChangesCount(0) |  | 
| 62 { |  | 
| 63 } |  | 
| 64 |  | 
| 65 SQLiteDatabase::~SQLiteDatabase() |  | 
| 66 { |  | 
| 67     close(); |  | 
| 68 } |  | 
| 69 |  | 
| 70 bool SQLiteDatabase::open(const String& filename, bool forWebSQLDatabase) |  | 
| 71 { |  | 
| 72     close(); |  | 
| 73 |  | 
| 74     m_openError = SQLiteFileSystem::openDatabase(filename, &m_db, forWebSQLDatab
     ase); |  | 
| 75     if (m_openError != SQLITE_OK) { |  | 
| 76         m_openErrorMessage = m_db ? sqlite3_errmsg(m_db) : "sqlite_open returned
      null"; |  | 
| 77         LOG_ERROR("SQLite database failed to load from %s\nCause - %s", filename
     .ascii().data(), |  | 
| 78             m_openErrorMessage.data()); |  | 
| 79         sqlite3_close(m_db); |  | 
| 80         m_db = 0; |  | 
| 81         return false; |  | 
| 82     } |  | 
| 83 |  | 
| 84     m_openError = sqlite3_extended_result_codes(m_db, 1); |  | 
| 85     if (m_openError != SQLITE_OK) { |  | 
| 86         m_openErrorMessage = sqlite3_errmsg(m_db); |  | 
| 87         LOG_ERROR("SQLite database error when enabling extended errors - %s", m_
     openErrorMessage.data()); |  | 
| 88         sqlite3_close(m_db); |  | 
| 89         m_db = 0; |  | 
| 90         return false; |  | 
| 91     } |  | 
| 92 |  | 
| 93     if (isOpen()) |  | 
| 94         m_openingThread = currentThread(); |  | 
| 95     else |  | 
| 96         m_openErrorMessage = "sqlite_open returned null"; |  | 
| 97 |  | 
| 98     if (!SQLiteStatement(*this, "PRAGMA temp_store = MEMORY;").executeCommand()) |  | 
| 99         LOG_ERROR("SQLite database could not set temp_store to memory"); |  | 
| 100 |  | 
| 101     return isOpen(); |  | 
| 102 } |  | 
| 103 |  | 
| 104 void SQLiteDatabase::close() |  | 
| 105 { |  | 
| 106     if (m_db) { |  | 
| 107         // FIXME: This is being called on the main thread during JS GC. <rdar://
     problem/5739818> |  | 
| 108         // ASSERT(currentThread() == m_openingThread); |  | 
| 109         sqlite3* db = m_db; |  | 
| 110         { |  | 
| 111             MutexLocker locker(m_databaseClosingMutex); |  | 
| 112             m_db = 0; |  | 
| 113         } |  | 
| 114         sqlite3_close(db); |  | 
| 115     } |  | 
| 116 |  | 
| 117     m_openingThread = 0; |  | 
| 118     m_openError = SQLITE_ERROR; |  | 
| 119     m_openErrorMessage = CString(); |  | 
| 120 } |  | 
| 121 |  | 
| 122 void SQLiteDatabase::interrupt() |  | 
| 123 { |  | 
| 124     m_interrupted = true; |  | 
| 125     while (!m_lockingMutex.tryLock()) { |  | 
| 126         MutexLocker locker(m_databaseClosingMutex); |  | 
| 127         if (!m_db) |  | 
| 128             return; |  | 
| 129         sqlite3_interrupt(m_db); |  | 
| 130         yield(); |  | 
| 131     } |  | 
| 132 |  | 
| 133     m_lockingMutex.unlock(); |  | 
| 134 } |  | 
| 135 |  | 
| 136 bool SQLiteDatabase::isInterrupted() |  | 
| 137 { |  | 
| 138     ASSERT(!m_lockingMutex.tryLock()); |  | 
| 139     return m_interrupted; |  | 
| 140 } |  | 
| 141 |  | 
| 142 void SQLiteDatabase::setFullsync(bool fsync) |  | 
| 143 { |  | 
| 144     if (fsync) |  | 
| 145         executeCommand("PRAGMA fullfsync = 1;"); |  | 
| 146     else |  | 
| 147         executeCommand("PRAGMA fullfsync = 0;"); |  | 
| 148 } |  | 
| 149 |  | 
| 150 int64_t SQLiteDatabase::maximumSize() |  | 
| 151 { |  | 
| 152     int64_t maxPageCount = 0; |  | 
| 153 |  | 
| 154     { |  | 
| 155         MutexLocker locker(m_authorizerLock); |  | 
| 156         enableAuthorizer(false); |  | 
| 157         SQLiteStatement statement(*this, "PRAGMA max_page_count"); |  | 
| 158         maxPageCount = statement.getColumnInt64(0); |  | 
| 159         enableAuthorizer(true); |  | 
| 160     } |  | 
| 161 |  | 
| 162     return maxPageCount * pageSize(); |  | 
| 163 } |  | 
| 164 |  | 
| 165 void SQLiteDatabase::setMaximumSize(int64_t size) |  | 
| 166 { |  | 
| 167     if (size < 0) |  | 
| 168         size = 0; |  | 
| 169 |  | 
| 170     int currentPageSize = pageSize(); |  | 
| 171 |  | 
| 172     ASSERT(currentPageSize || !m_db); |  | 
| 173     int64_t newMaxPageCount = currentPageSize ? size / currentPageSize : 0; |  | 
| 174 |  | 
| 175     MutexLocker locker(m_authorizerLock); |  | 
| 176     enableAuthorizer(false); |  | 
| 177 |  | 
| 178     SQLiteStatement statement(*this, "PRAGMA max_page_count = " + String::number
     (newMaxPageCount)); |  | 
| 179     statement.prepare(); |  | 
| 180     if (statement.step() != SQLResultRow) |  | 
| 181 #if OS(WIN) |  | 
| 182         LOG_ERROR("Failed to set maximum size of database to %I64i bytes", stati
     c_cast<long long>(size)); |  | 
| 183 #else |  | 
| 184         LOG_ERROR("Failed to set maximum size of database to %lli bytes", static
     _cast<long long>(size)); |  | 
| 185 #endif |  | 
| 186 |  | 
| 187     enableAuthorizer(true); |  | 
| 188 |  | 
| 189 } |  | 
| 190 |  | 
| 191 int SQLiteDatabase::pageSize() |  | 
| 192 { |  | 
| 193     // Since the page size of a database is locked in at creation and therefore 
     cannot be dynamic, |  | 
| 194     // we can cache the value for future use |  | 
| 195     if (m_pageSize == -1) { |  | 
| 196         MutexLocker locker(m_authorizerLock); |  | 
| 197         enableAuthorizer(false); |  | 
| 198 |  | 
| 199         SQLiteStatement statement(*this, "PRAGMA page_size"); |  | 
| 200         m_pageSize = statement.getColumnInt(0); |  | 
| 201 |  | 
| 202         enableAuthorizer(true); |  | 
| 203     } |  | 
| 204 |  | 
| 205     return m_pageSize; |  | 
| 206 } |  | 
| 207 |  | 
| 208 int64_t SQLiteDatabase::freeSpaceSize() |  | 
| 209 { |  | 
| 210     int64_t freelistCount = 0; |  | 
| 211 |  | 
| 212     { |  | 
| 213         MutexLocker locker(m_authorizerLock); |  | 
| 214         enableAuthorizer(false); |  | 
| 215         // Note: freelist_count was added in SQLite 3.4.1. |  | 
| 216         SQLiteStatement statement(*this, "PRAGMA freelist_count"); |  | 
| 217         freelistCount = statement.getColumnInt64(0); |  | 
| 218         enableAuthorizer(true); |  | 
| 219     } |  | 
| 220 |  | 
| 221     return freelistCount * pageSize(); |  | 
| 222 } |  | 
| 223 |  | 
| 224 int64_t SQLiteDatabase::totalSize() |  | 
| 225 { |  | 
| 226     int64_t pageCount = 0; |  | 
| 227 |  | 
| 228     { |  | 
| 229         MutexLocker locker(m_authorizerLock); |  | 
| 230         enableAuthorizer(false); |  | 
| 231         SQLiteStatement statement(*this, "PRAGMA page_count"); |  | 
| 232         pageCount = statement.getColumnInt64(0); |  | 
| 233         enableAuthorizer(true); |  | 
| 234     } |  | 
| 235 |  | 
| 236     return pageCount * pageSize(); |  | 
| 237 } |  | 
| 238 |  | 
| 239 void SQLiteDatabase::setSynchronous(SynchronousPragma sync) |  | 
| 240 { |  | 
| 241     executeCommand("PRAGMA synchronous = " + String::number(sync)); |  | 
| 242 } |  | 
| 243 |  | 
| 244 void SQLiteDatabase::setBusyTimeout(int ms) |  | 
| 245 { |  | 
| 246     if (m_db) |  | 
| 247         sqlite3_busy_timeout(m_db, ms); |  | 
| 248     else |  | 
| 249         LOG(SQLDatabase, "BusyTimeout set on non-open database"); |  | 
| 250 } |  | 
| 251 |  | 
| 252 void SQLiteDatabase::setBusyHandler(int(*handler)(void*, int)) |  | 
| 253 { |  | 
| 254     if (m_db) |  | 
| 255         sqlite3_busy_handler(m_db, handler, NULL); |  | 
| 256     else |  | 
| 257         LOG(SQLDatabase, "Busy handler set on non-open database"); |  | 
| 258 } |  | 
| 259 |  | 
| 260 bool SQLiteDatabase::executeCommand(const String& sql) |  | 
| 261 { |  | 
| 262     return SQLiteStatement(*this, sql).executeCommand(); |  | 
| 263 } |  | 
| 264 |  | 
| 265 bool SQLiteDatabase::returnsAtLeastOneResult(const String& sql) |  | 
| 266 { |  | 
| 267     return SQLiteStatement(*this, sql).returnsAtLeastOneResult(); |  | 
| 268 } |  | 
| 269 |  | 
| 270 bool SQLiteDatabase::tableExists(const String& tablename) |  | 
| 271 { |  | 
| 272     if (!isOpen()) |  | 
| 273         return false; |  | 
| 274 |  | 
| 275     String statement = "SELECT name FROM sqlite_master WHERE type = 'table' AND 
     name = '" + tablename + "';"; |  | 
| 276 |  | 
| 277     SQLiteStatement sql(*this, statement); |  | 
| 278     sql.prepare(); |  | 
| 279     return sql.step() == SQLITE_ROW; |  | 
| 280 } |  | 
| 281 |  | 
| 282 void SQLiteDatabase::clearAllTables() |  | 
| 283 { |  | 
| 284     String query = "SELECT name FROM sqlite_master WHERE type='table';"; |  | 
| 285     Vector<String> tables; |  | 
| 286     if (!SQLiteStatement(*this, query).returnTextResults(0, tables)) { |  | 
| 287         LOG(SQLDatabase, "Unable to retrieve list of tables from database"); |  | 
| 288         return; |  | 
| 289     } |  | 
| 290 |  | 
| 291     for (Vector<String>::iterator table = tables.begin(); table != tables.end();
      ++table ) { |  | 
| 292         if (*table == "sqlite_sequence") |  | 
| 293             continue; |  | 
| 294         if (!executeCommand("DROP TABLE " + *table)) |  | 
| 295             LOG(SQLDatabase, "Unable to drop table %s", (*table).ascii().data())
     ; |  | 
| 296     } |  | 
| 297 } |  | 
| 298 |  | 
| 299 int SQLiteDatabase::runVacuumCommand() |  | 
| 300 { |  | 
| 301     if (!executeCommand("VACUUM;")) |  | 
| 302         LOG(SQLDatabase, "Unable to vacuum database - %s", lastErrorMsg()); |  | 
| 303     return lastError(); |  | 
| 304 } |  | 
| 305 |  | 
| 306 int SQLiteDatabase::runIncrementalVacuumCommand() |  | 
| 307 { |  | 
| 308     MutexLocker locker(m_authorizerLock); |  | 
| 309     enableAuthorizer(false); |  | 
| 310 |  | 
| 311     if (!executeCommand("PRAGMA incremental_vacuum")) |  | 
| 312         LOG(SQLDatabase, "Unable to run incremental vacuum - %s", lastErrorMsg()
     ); |  | 
| 313 |  | 
| 314     enableAuthorizer(true); |  | 
| 315     return lastError(); |  | 
| 316 } |  | 
| 317 |  | 
| 318 int64_t SQLiteDatabase::lastInsertRowID() |  | 
| 319 { |  | 
| 320     if (!m_db) |  | 
| 321         return 0; |  | 
| 322     return sqlite3_last_insert_rowid(m_db); |  | 
| 323 } |  | 
| 324 |  | 
| 325 void SQLiteDatabase::updateLastChangesCount() |  | 
| 326 { |  | 
| 327     if (!m_db) |  | 
| 328         return; |  | 
| 329 |  | 
| 330     m_lastChangesCount = sqlite3_total_changes(m_db); |  | 
| 331 } |  | 
| 332 |  | 
| 333 int SQLiteDatabase::lastChanges() |  | 
| 334 { |  | 
| 335     if (!m_db) |  | 
| 336         return 0; |  | 
| 337 |  | 
| 338     return sqlite3_total_changes(m_db) - m_lastChangesCount; |  | 
| 339 } |  | 
| 340 |  | 
| 341 int SQLiteDatabase::lastError() |  | 
| 342 { |  | 
| 343     return m_db ? sqlite3_errcode(m_db) : m_openError; |  | 
| 344 } |  | 
| 345 |  | 
| 346 const char* SQLiteDatabase::lastErrorMsg() |  | 
| 347 { |  | 
| 348     if (m_db) |  | 
| 349         return sqlite3_errmsg(m_db); |  | 
| 350     return m_openErrorMessage.isNull() ? notOpenErrorMessage : m_openErrorMessag
     e.data(); |  | 
| 351 } |  | 
| 352 |  | 
| 353 #ifndef NDEBUG |  | 
| 354 void SQLiteDatabase::disableThreadingChecks() |  | 
| 355 { |  | 
| 356     // This doesn't guarantee that SQList was compiled with -DTHREADSAFE, or tha
     t you haven't turned off the mutexes. |  | 
| 357 #if SQLITE_VERSION_NUMBER >= 3003001 |  | 
| 358     m_sharable = true; |  | 
| 359 #else |  | 
| 360     ASSERT(0); // Your SQLite doesn't support sharing handles across threads. |  | 
| 361 #endif |  | 
| 362 } |  | 
| 363 #endif |  | 
| 364 |  | 
| 365 int SQLiteDatabase::authorizerFunction(void* userData, int actionCode, const cha
     r* parameter1, const char* parameter2, const char* /*databaseName*/, const char*
      /*trigger_or_view*/) |  | 
| 366 { |  | 
| 367     DatabaseAuthorizer* auth = static_cast<DatabaseAuthorizer*>(userData); |  | 
| 368     ASSERT(auth); |  | 
| 369 |  | 
| 370     switch (actionCode) { |  | 
| 371         case SQLITE_CREATE_INDEX: |  | 
| 372             return auth->createIndex(parameter1, parameter2); |  | 
| 373         case SQLITE_CREATE_TABLE: |  | 
| 374             return auth->createTable(parameter1); |  | 
| 375         case SQLITE_CREATE_TEMP_INDEX: |  | 
| 376             return auth->createTempIndex(parameter1, parameter2); |  | 
| 377         case SQLITE_CREATE_TEMP_TABLE: |  | 
| 378             return auth->createTempTable(parameter1); |  | 
| 379         case SQLITE_CREATE_TEMP_TRIGGER: |  | 
| 380             return auth->createTempTrigger(parameter1, parameter2); |  | 
| 381         case SQLITE_CREATE_TEMP_VIEW: |  | 
| 382             return auth->createTempView(parameter1); |  | 
| 383         case SQLITE_CREATE_TRIGGER: |  | 
| 384             return auth->createTrigger(parameter1, parameter2); |  | 
| 385         case SQLITE_CREATE_VIEW: |  | 
| 386             return auth->createView(parameter1); |  | 
| 387         case SQLITE_DELETE: |  | 
| 388             return auth->allowDelete(parameter1); |  | 
| 389         case SQLITE_DROP_INDEX: |  | 
| 390             return auth->dropIndex(parameter1, parameter2); |  | 
| 391         case SQLITE_DROP_TABLE: |  | 
| 392             return auth->dropTable(parameter1); |  | 
| 393         case SQLITE_DROP_TEMP_INDEX: |  | 
| 394             return auth->dropTempIndex(parameter1, parameter2); |  | 
| 395         case SQLITE_DROP_TEMP_TABLE: |  | 
| 396             return auth->dropTempTable(parameter1); |  | 
| 397         case SQLITE_DROP_TEMP_TRIGGER: |  | 
| 398             return auth->dropTempTrigger(parameter1, parameter2); |  | 
| 399         case SQLITE_DROP_TEMP_VIEW: |  | 
| 400             return auth->dropTempView(parameter1); |  | 
| 401         case SQLITE_DROP_TRIGGER: |  | 
| 402             return auth->dropTrigger(parameter1, parameter2); |  | 
| 403         case SQLITE_DROP_VIEW: |  | 
| 404             return auth->dropView(parameter1); |  | 
| 405         case SQLITE_INSERT: |  | 
| 406             return auth->allowInsert(parameter1); |  | 
| 407         case SQLITE_PRAGMA: |  | 
| 408             return auth->allowPragma(parameter1, parameter2); |  | 
| 409         case SQLITE_READ: |  | 
| 410             return auth->allowRead(parameter1, parameter2); |  | 
| 411         case SQLITE_SELECT: |  | 
| 412             return auth->allowSelect(); |  | 
| 413         case SQLITE_TRANSACTION: |  | 
| 414             return auth->allowTransaction(); |  | 
| 415         case SQLITE_UPDATE: |  | 
| 416             return auth->allowUpdate(parameter1, parameter2); |  | 
| 417         case SQLITE_ATTACH: |  | 
| 418             return auth->allowAttach(parameter1); |  | 
| 419         case SQLITE_DETACH: |  | 
| 420             return auth->allowDetach(parameter1); |  | 
| 421         case SQLITE_ALTER_TABLE: |  | 
| 422             return auth->allowAlterTable(parameter1, parameter2); |  | 
| 423         case SQLITE_REINDEX: |  | 
| 424             return auth->allowReindex(parameter1); |  | 
| 425 #if SQLITE_VERSION_NUMBER >= 3003013 |  | 
| 426         case SQLITE_ANALYZE: |  | 
| 427             return auth->allowAnalyze(parameter1); |  | 
| 428         case SQLITE_CREATE_VTABLE: |  | 
| 429             return auth->createVTable(parameter1, parameter2); |  | 
| 430         case SQLITE_DROP_VTABLE: |  | 
| 431             return auth->dropVTable(parameter1, parameter2); |  | 
| 432         case SQLITE_FUNCTION: |  | 
| 433             return auth->allowFunction(parameter2); |  | 
| 434 #endif |  | 
| 435         default: |  | 
| 436             ASSERT_NOT_REACHED(); |  | 
| 437             return SQLAuthDeny; |  | 
| 438     } |  | 
| 439 } |  | 
| 440 |  | 
| 441 void SQLiteDatabase::setAuthorizer(PassRefPtr<DatabaseAuthorizer> auth) |  | 
| 442 { |  | 
| 443     if (!m_db) { |  | 
| 444         LOG_ERROR("Attempt to set an authorizer on a non-open SQL database"); |  | 
| 445         ASSERT_NOT_REACHED(); |  | 
| 446         return; |  | 
| 447     } |  | 
| 448 |  | 
| 449     MutexLocker locker(m_authorizerLock); |  | 
| 450 |  | 
| 451     m_authorizer = auth; |  | 
| 452 |  | 
| 453     enableAuthorizer(true); |  | 
| 454 } |  | 
| 455 |  | 
| 456 void SQLiteDatabase::enableAuthorizer(bool enable) |  | 
| 457 { |  | 
| 458     if (m_authorizer && enable) |  | 
| 459         sqlite3_set_authorizer(m_db, SQLiteDatabase::authorizerFunction, m_autho
     rizer.get()); |  | 
| 460     else |  | 
| 461         sqlite3_set_authorizer(m_db, NULL, 0); |  | 
| 462 } |  | 
| 463 |  | 
| 464 bool SQLiteDatabase::isAutoCommitOn() const |  | 
| 465 { |  | 
| 466     return sqlite3_get_autocommit(m_db); |  | 
| 467 } |  | 
| 468 |  | 
| 469 bool SQLiteDatabase::turnOnIncrementalAutoVacuum() |  | 
| 470 { |  | 
| 471     SQLiteStatement statement(*this, "PRAGMA auto_vacuum"); |  | 
| 472     int autoVacuumMode = statement.getColumnInt(0); |  | 
| 473     int error = lastError(); |  | 
| 474 |  | 
| 475     // Check if we got an error while trying to get the value of the auto_vacuum
      flag. |  | 
| 476     // If we got a SQLITE_BUSY error, then there's probably another transaction 
     in |  | 
| 477     // progress on this database. In this case, keep the current value of the |  | 
| 478     // auto_vacuum flag and try to set it to INCREMENTAL the next time we open t
     his |  | 
| 479     // database. If the error is not SQLITE_BUSY, then we probably ran into a mo
     re |  | 
| 480     // serious problem and should return false (to log an error message). |  | 
| 481     if (error != SQLITE_ROW) |  | 
| 482         return false; |  | 
| 483 |  | 
| 484     switch (autoVacuumMode) { |  | 
| 485     case AutoVacuumIncremental: |  | 
| 486         return true; |  | 
| 487     case AutoVacuumFull: |  | 
| 488         return executeCommand("PRAGMA auto_vacuum = 2"); |  | 
| 489     case AutoVacuumNone: |  | 
| 490     default: |  | 
| 491         if (!executeCommand("PRAGMA auto_vacuum = 2")) |  | 
| 492             return false; |  | 
| 493         runVacuumCommand(); |  | 
| 494         error = lastError(); |  | 
| 495         return (error == SQLITE_OK); |  | 
| 496     } |  | 
| 497 } |  | 
| 498 |  | 
| 499 } // namespace WebCore |  | 
| OLD | NEW | 
|---|