Initial refactoring of database functionality into the manager and server.
[WebKit-https.git] / Source / WebCore / Modules / webdatabase / DatabaseSync.cpp
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 "DatabaseSync.h"
33
34 #if ENABLE(SQL_DATABASE)
35
36 #include "DatabaseCallback.h"
37 #include "DatabaseManager.h"
38 #include "Logging.h"
39 #include "SQLException.h"
40 #include "SQLTransactionSync.h"
41 #include "SQLTransactionSyncCallback.h"
42 #include "ScriptExecutionContext.h"
43 #include "SecurityOrigin.h"
44 #include <wtf/PassRefPtr.h>
45 #include <wtf/RefPtr.h>
46 #include <wtf/text/CString.h>
47
48 namespace WebCore {
49
50 DatabaseSync::DatabaseSync(ScriptExecutionContext* context, const String& name, const String& expectedVersion,
51                            const String& displayName, unsigned long estimatedSize)
52     : AbstractDatabase(context, name, expectedVersion, displayName, estimatedSize, SyncDatabase)
53 {
54 }
55
56 DatabaseSync::~DatabaseSync()
57 {
58     ASSERT(m_scriptExecutionContext->isContextThread());
59
60     if (opened()) {
61         DatabaseManager::manager().removeOpenDatabase(this);
62         closeDatabase();
63     }
64 }
65
66 void DatabaseSync::changeVersion(const String& oldVersion, const String& newVersion, PassRefPtr<SQLTransactionSyncCallback> changeVersionCallback, ExceptionCode& ec)
67 {
68     ASSERT(m_scriptExecutionContext->isContextThread());
69
70     if (sqliteDatabase().transactionInProgress()) {
71         reportChangeVersionResult(1, SQLException::DATABASE_ERR, 0);
72         setLastErrorMessage("unable to changeVersion from within a transaction");
73         ec = SQLException::DATABASE_ERR;
74         return;
75     }
76
77     RefPtr<SQLTransactionSync> transaction = SQLTransactionSync::create(this, changeVersionCallback, false);
78     if ((ec = transaction->begin())) {
79         ASSERT(!lastErrorMessage().isEmpty());
80         return;
81     }
82
83     String actualVersion;
84     if (!getVersionFromDatabase(actualVersion)) {
85         reportChangeVersionResult(2, SQLException::UNKNOWN_ERR, sqliteDatabase().lastError());
86         setLastErrorMessage("unable to read the current version", sqliteDatabase().lastError(), sqliteDatabase().lastErrorMsg());
87         ec = SQLException::UNKNOWN_ERR;
88         return;
89     }
90
91     if (actualVersion != oldVersion) {
92         reportChangeVersionResult(3, SQLException::VERSION_ERR, 0);
93         setLastErrorMessage("current version of the database and `oldVersion` argument do not match");
94         ec = SQLException::VERSION_ERR;
95         return;
96     }
97
98     if ((ec = transaction->execute())) {
99         ASSERT(!lastErrorMessage().isEmpty());
100         return;
101     }
102
103     if (!setVersionInDatabase(newVersion)) {
104         reportChangeVersionResult(4, SQLException::UNKNOWN_ERR, sqliteDatabase().lastError());
105         setLastErrorMessage("unable to set the new version", sqliteDatabase().lastError(), sqliteDatabase().lastErrorMsg());
106         ec = SQLException::UNKNOWN_ERR;
107         return;
108     }
109
110     if ((ec = transaction->commit())) {
111         ASSERT(!lastErrorMessage().isEmpty());
112         setCachedVersion(oldVersion);
113         return;
114     }
115
116     reportChangeVersionResult(0, -1, 0); // OK
117
118     setExpectedVersion(newVersion);
119     setLastErrorMessage("");
120 }
121
122 void DatabaseSync::transaction(PassRefPtr<SQLTransactionSyncCallback> callback, ExceptionCode& ec)
123 {
124     runTransaction(callback, false, ec);
125 }
126
127 void DatabaseSync::readTransaction(PassRefPtr<SQLTransactionSyncCallback> callback, ExceptionCode& ec)
128 {
129     runTransaction(callback, true, ec);
130 }
131
132 void DatabaseSync::runTransaction(PassRefPtr<SQLTransactionSyncCallback> callback, bool readOnly, ExceptionCode& ec)
133 {
134     ASSERT(m_scriptExecutionContext->isContextThread());
135
136     if (sqliteDatabase().transactionInProgress()) {
137         setLastErrorMessage("unable to start a transaction from within a transaction");
138         ec = SQLException::DATABASE_ERR;
139         return;
140     }
141
142     RefPtr<SQLTransactionSync> transaction = SQLTransactionSync::create(this, callback, readOnly);
143     if ((ec = transaction->begin()) || (ec = transaction->execute()) || (ec = transaction->commit())) {
144         ASSERT(!lastErrorMessage().isEmpty());
145         transaction->rollback();
146     }
147
148     setLastErrorMessage("");
149 }
150
151 void DatabaseSync::markAsDeletedAndClose()
152 {
153     // FIXME: need to do something similar to closeImmediately(), but in a sync way
154 }
155
156 class CloseSyncDatabaseOnContextThreadTask : public ScriptExecutionContext::Task {
157 public:
158     static PassOwnPtr<CloseSyncDatabaseOnContextThreadTask> create(PassRefPtr<DatabaseSync> database)
159     {
160         return adoptPtr(new CloseSyncDatabaseOnContextThreadTask(database));
161     }
162
163     virtual void performTask(ScriptExecutionContext*)
164     {
165         m_database->closeImmediately();
166     }
167
168 private:
169     CloseSyncDatabaseOnContextThreadTask(PassRefPtr<DatabaseSync> database)
170         : m_database(database)
171     {
172     }
173
174     RefPtr<DatabaseSync> m_database;
175 };
176
177 void DatabaseSync::closeImmediately()
178 {
179     ASSERT(m_scriptExecutionContext->isContextThread());
180
181     if (!opened())
182         return;
183
184     logErrorMessage("forcibly closing database");
185     DatabaseManager::manager().removeOpenDatabase(this);
186     closeDatabase();
187 }
188
189 } // namespace WebCore
190
191 #endif // ENABLE(SQL_DATABASE)