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