Home | History | Annotate | Download | only in webdatabase
      1 /*
      2  * Copyright (C) 2010 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "modules/webdatabase/DatabaseSync.h"
     33 
     34 #include "bindings/v8/ExceptionState.h"
     35 #include "core/dom/ExceptionCode.h"
     36 #include "core/dom/ExecutionContext.h"
     37 #include "platform/Logging.h"
     38 #include "modules/webdatabase/DatabaseCallback.h"
     39 #include "modules/webdatabase/DatabaseContext.h"
     40 #include "modules/webdatabase/DatabaseManager.h"
     41 #include "modules/webdatabase/DatabaseTracker.h"
     42 #include "modules/webdatabase/SQLError.h"
     43 #include "modules/webdatabase/SQLTransactionSync.h"
     44 #include "modules/webdatabase/SQLTransactionSyncCallback.h"
     45 #include "wtf/PassRefPtr.h"
     46 #include "wtf/RefPtr.h"
     47 #include "wtf/text/CString.h"
     48 
     49 namespace WebCore {
     50 
     51 PassRefPtr<DatabaseSync> DatabaseSync::create(ExecutionContext*, PassRefPtr<DatabaseBackendBase> backend)
     52 {
     53     return static_cast<DatabaseSync*>(backend.get());
     54 }
     55 
     56 DatabaseSync::DatabaseSync(PassRefPtr<DatabaseContext> databaseContext,
     57     const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
     58     : DatabaseBase(databaseContext->executionContext())
     59     , DatabaseBackendSync(databaseContext, name, expectedVersion, displayName, estimatedSize)
     60 {
     61     ScriptWrappable::init(this);
     62     setFrontend(this);
     63 }
     64 
     65 DatabaseSync::~DatabaseSync()
     66 {
     67     ASSERT(m_executionContext->isContextThread());
     68 }
     69 
     70 PassRefPtr<DatabaseBackendSync> DatabaseSync::backend()
     71 {
     72     return this;
     73 }
     74 
     75 void DatabaseSync::changeVersion(const String& oldVersion, const String& newVersion, PassOwnPtr<SQLTransactionSyncCallback> changeVersionCallback, ExceptionState& exceptionState)
     76 {
     77     ASSERT(m_executionContext->isContextThread());
     78 
     79     if (sqliteDatabase().transactionInProgress()) {
     80         reportChangeVersionResult(1, SQLError::DATABASE_ERR, 0);
     81         setLastErrorMessage("unable to changeVersion from within a transaction");
     82         exceptionState.throwUninformativeAndGenericDOMException(SQLDatabaseError);
     83         return;
     84     }
     85 
     86     RefPtr<SQLTransactionSync> transaction = SQLTransactionSync::create(this, changeVersionCallback, false);
     87     transaction->begin(exceptionState);
     88     if (exceptionState.hadException()) {
     89         ASSERT(!lastErrorMessage().isEmpty());
     90         return;
     91     }
     92 
     93     String actualVersion;
     94     if (!getVersionFromDatabase(actualVersion)) {
     95         reportChangeVersionResult(2, SQLError::UNKNOWN_ERR, sqliteDatabase().lastError());
     96         setLastErrorMessage("unable to read the current version", sqliteDatabase().lastError(), sqliteDatabase().lastErrorMsg());
     97         exceptionState.throwDOMException(UnknownError, SQLError::unknownErrorMessage);
     98         return;
     99     }
    100 
    101     if (actualVersion != oldVersion) {
    102         reportChangeVersionResult(3, SQLError::VERSION_ERR, 0);
    103         setLastErrorMessage("current version of the database and `oldVersion` argument do not match");
    104         exceptionState.throwDOMException(VersionError, SQLError::versionErrorMessage);
    105         return;
    106     }
    107 
    108 
    109     transaction->execute(exceptionState);
    110     if (exceptionState.hadException()) {
    111         ASSERT(!lastErrorMessage().isEmpty());
    112         return;
    113     }
    114 
    115     if (!setVersionInDatabase(newVersion)) {
    116         reportChangeVersionResult(4, SQLError::UNKNOWN_ERR, sqliteDatabase().lastError());
    117         setLastErrorMessage("unable to set the new version", sqliteDatabase().lastError(), sqliteDatabase().lastErrorMsg());
    118         exceptionState.throwDOMException(UnknownError, SQLError::unknownErrorMessage);
    119         return;
    120     }
    121 
    122     transaction->commit(exceptionState);
    123     if (exceptionState.hadException()) {
    124         ASSERT(!lastErrorMessage().isEmpty());
    125         setCachedVersion(oldVersion);
    126         return;
    127     }
    128 
    129     reportChangeVersionResult(0, -1, 0); // OK
    130 
    131     setExpectedVersion(newVersion);
    132     setLastErrorMessage("");
    133 }
    134 
    135 void DatabaseSync::transaction(PassOwnPtr<SQLTransactionSyncCallback> callback, ExceptionState& exceptionState)
    136 {
    137     runTransaction(callback, false, exceptionState);
    138 }
    139 
    140 void DatabaseSync::readTransaction(PassOwnPtr<SQLTransactionSyncCallback> callback, ExceptionState& exceptionState)
    141 {
    142     runTransaction(callback, true, exceptionState);
    143 }
    144 
    145 void DatabaseSync::rollbackTransaction(PassRefPtr<SQLTransactionSync> transaction)
    146 {
    147     ASSERT(!lastErrorMessage().isEmpty());
    148     transaction->rollback();
    149     setLastErrorMessage("");
    150     return;
    151 }
    152 
    153 void DatabaseSync::runTransaction(PassOwnPtr<SQLTransactionSyncCallback> callback, bool readOnly, ExceptionState& exceptionState)
    154 {
    155     ASSERT(m_executionContext->isContextThread());
    156 
    157     if (sqliteDatabase().transactionInProgress()) {
    158         setLastErrorMessage("unable to start a transaction from within a transaction");
    159         exceptionState.throwUninformativeAndGenericDOMException(SQLDatabaseError);
    160         return;
    161     }
    162 
    163     RefPtr<SQLTransactionSync> transaction = SQLTransactionSync::create(this, callback, readOnly);
    164     transaction->begin(exceptionState);
    165     if (exceptionState.hadException()) {
    166         rollbackTransaction(transaction);
    167         return;
    168     }
    169 
    170     transaction->execute(exceptionState);
    171     if (exceptionState.hadException()) {
    172         rollbackTransaction(transaction);
    173         return;
    174     }
    175 
    176     transaction->commit(exceptionState);
    177     if (exceptionState.hadException()) {
    178         rollbackTransaction(transaction);
    179         return;
    180     }
    181 
    182     setLastErrorMessage("");
    183 }
    184 
    185 void DatabaseSync::closeImmediately()
    186 {
    187     ASSERT(m_executionContext->isContextThread());
    188 
    189     if (!opened())
    190         return;
    191 
    192     logErrorMessage("forcibly closing database");
    193     closeDatabase();
    194 }
    195 
    196 } // namespace WebCore
    197