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