• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007, 2008, 2013 Apple 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
6  * are met:
7  *
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  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "config.h"
30 #include "modules/webdatabase/Database.h"
31 
32 #include "core/dom/CrossThreadTask.h"
33 #include "core/dom/Document.h"
34 #include "core/dom/ExecutionContext.h"
35 #include "core/html/VoidCallback.h"
36 #include "core/page/Page.h"
37 #include "platform/Logging.h"
38 #include "modules/webdatabase/sqlite/SQLiteStatement.h"
39 #include "modules/webdatabase/ChangeVersionData.h"
40 #include "modules/webdatabase/DatabaseCallback.h"
41 #include "modules/webdatabase/DatabaseContext.h"
42 #include "modules/webdatabase/DatabaseManager.h"
43 #include "modules/webdatabase/DatabaseTask.h"
44 #include "modules/webdatabase/DatabaseThread.h"
45 #include "modules/webdatabase/DatabaseTracker.h"
46 #include "modules/webdatabase/SQLError.h"
47 #include "modules/webdatabase/SQLTransaction.h"
48 #include "modules/webdatabase/SQLTransactionCallback.h"
49 #include "modules/webdatabase/SQLTransactionErrorCallback.h"
50 #include "platform/weborigin/SecurityOrigin.h"
51 #include "wtf/OwnPtr.h"
52 #include "wtf/PassOwnPtr.h"
53 #include "wtf/PassRefPtr.h"
54 #include "wtf/RefPtr.h"
55 #include "wtf/StdLibExtras.h"
56 #include "wtf/text/CString.h"
57 
58 namespace WebCore {
59 
create(ExecutionContext *,PassRefPtr<DatabaseBackendBase> backend)60 PassRefPtr<Database> Database::create(ExecutionContext*, PassRefPtr<DatabaseBackendBase> backend)
61 {
62     // FIXME: Currently, we're only simulating the backend by return the
63     // frontend database as its own the backend. When we split the 2 apart,
64     // this create() function should be changed to be a factory method for
65     // instantiating the backend.
66     return static_cast<Database*>(backend.get());
67 }
68 
Database(PassRefPtr<DatabaseContext> databaseContext,const String & name,const String & expectedVersion,const String & displayName,unsigned long estimatedSize)69 Database::Database(PassRefPtr<DatabaseContext> databaseContext,
70     const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
71     : DatabaseBase(databaseContext->executionContext())
72     , DatabaseBackend(databaseContext, name, expectedVersion, displayName, estimatedSize)
73     , m_databaseContext(DatabaseBackend::databaseContext())
74 {
75     ScriptWrappable::init(this);
76     m_databaseThreadSecurityOrigin = m_contextThreadSecurityOrigin->isolatedCopy();
77     setFrontend(this);
78 
79     ASSERT(m_databaseContext->databaseThread());
80 }
81 
82 class DerefContextTask : public ExecutionContextTask {
83 public:
create(PassRefPtr<ExecutionContext> context)84     static PassOwnPtr<DerefContextTask> create(PassRefPtr<ExecutionContext> context)
85     {
86         return adoptPtr(new DerefContextTask(context));
87     }
88 
performTask(ExecutionContext * context)89     virtual void performTask(ExecutionContext* context)
90     {
91         ASSERT_UNUSED(context, context == m_context);
92         m_context.clear();
93     }
94 
isCleanupTask() const95     virtual bool isCleanupTask() const { return true; }
96 
97 private:
DerefContextTask(PassRefPtr<ExecutionContext> context)98     DerefContextTask(PassRefPtr<ExecutionContext> context)
99         : m_context(context)
100     {
101     }
102 
103     RefPtr<ExecutionContext> m_context;
104 };
105 
~Database()106 Database::~Database()
107 {
108     // The reference to the ExecutionContext needs to be cleared on the JavaScript thread. If we're on that thread already, we can just let the RefPtr's destruction do the dereffing.
109     if (!m_executionContext->isContextThread()) {
110         // Grab a pointer to the script execution here because we're releasing it when we pass it to
111         // DerefContextTask::create.
112         ExecutionContext* executionContext = m_executionContext.get();
113 
114         executionContext->postTask(DerefContextTask::create(m_executionContext.release()));
115     }
116 }
117 
from(DatabaseBackend * backend)118 Database* Database::from(DatabaseBackend* backend)
119 {
120     return static_cast<Database*>(backend->m_frontend);
121 }
122 
backend()123 PassRefPtr<DatabaseBackend> Database::backend()
124 {
125     return this;
126 }
127 
version() const128 String Database::version() const
129 {
130     return DatabaseBackendBase::version();
131 }
132 
closeImmediately()133 void Database::closeImmediately()
134 {
135     ASSERT(m_executionContext->isContextThread());
136     DatabaseThread* databaseThread = databaseContext()->databaseThread();
137     if (databaseThread && !databaseThread->terminationRequested() && opened()) {
138         logErrorMessage("forcibly closing database");
139         databaseThread->scheduleTask(DatabaseCloseTask::create(this, 0));
140     }
141 }
142 
changeVersion(const String & oldVersion,const String & newVersion,PassOwnPtr<SQLTransactionCallback> callback,PassOwnPtr<SQLTransactionErrorCallback> errorCallback,PassOwnPtr<VoidCallback> successCallback)143 void Database::changeVersion(const String& oldVersion, const String& newVersion, PassOwnPtr<SQLTransactionCallback> callback, PassOwnPtr<SQLTransactionErrorCallback> errorCallback, PassOwnPtr<VoidCallback> successCallback)
144 {
145     ChangeVersionData data(oldVersion, newVersion);
146     runTransaction(callback, errorCallback, successCallback, false, &data);
147 }
148 
transaction(PassOwnPtr<SQLTransactionCallback> callback,PassOwnPtr<SQLTransactionErrorCallback> errorCallback,PassOwnPtr<VoidCallback> successCallback)149 void Database::transaction(PassOwnPtr<SQLTransactionCallback> callback, PassOwnPtr<SQLTransactionErrorCallback> errorCallback, PassOwnPtr<VoidCallback> successCallback)
150 {
151     runTransaction(callback, errorCallback, successCallback, false);
152 }
153 
readTransaction(PassOwnPtr<SQLTransactionCallback> callback,PassOwnPtr<SQLTransactionErrorCallback> errorCallback,PassOwnPtr<VoidCallback> successCallback)154 void Database::readTransaction(PassOwnPtr<SQLTransactionCallback> callback, PassOwnPtr<SQLTransactionErrorCallback> errorCallback, PassOwnPtr<VoidCallback> successCallback)
155 {
156     runTransaction(callback, errorCallback, successCallback, true);
157 }
158 
callTransactionErrorCallback(ExecutionContext *,PassOwnPtr<SQLTransactionErrorCallback> callback,PassRefPtr<SQLError> error)159 static void callTransactionErrorCallback(ExecutionContext*, PassOwnPtr<SQLTransactionErrorCallback> callback, PassRefPtr<SQLError> error)
160 {
161     callback->handleEvent(error.get());
162 }
163 
runTransaction(PassOwnPtr<SQLTransactionCallback> callback,PassOwnPtr<SQLTransactionErrorCallback> errorCallback,PassOwnPtr<VoidCallback> successCallback,bool readOnly,const ChangeVersionData * changeVersionData)164 void Database::runTransaction(PassOwnPtr<SQLTransactionCallback> callback, PassOwnPtr<SQLTransactionErrorCallback> errorCallback,
165     PassOwnPtr<VoidCallback> successCallback, bool readOnly, const ChangeVersionData* changeVersionData)
166 {
167     // FIXME: Rather than passing errorCallback to SQLTransaction and then sometimes firing it ourselves,
168     // this code should probably be pushed down into DatabaseBackend so that we only create the SQLTransaction
169     // if we're actually going to run it.
170 #if !ASSERT_DISABLED
171     SQLTransactionErrorCallback* originalErrorCallback = errorCallback.get();
172 #endif
173     RefPtr<SQLTransaction> transaction = SQLTransaction::create(this, callback, successCallback, errorCallback, readOnly);
174     RefPtr<SQLTransactionBackend> transactionBackend = backend()->runTransaction(transaction, readOnly, changeVersionData);
175     if (!transactionBackend) {
176         OwnPtr<SQLTransactionErrorCallback> callback = transaction->releaseErrorCallback();
177         ASSERT(callback == originalErrorCallback);
178         if (callback) {
179             RefPtr<SQLError> error = SQLError::create(SQLError::UNKNOWN_ERR, "database has been closed");
180             executionContext()->postTask(createCallbackTask(&callTransactionErrorCallback, callback.release(), error.release()));
181         }
182     }
183 }
184 
185 class DeliverPendingCallbackTask : public ExecutionContextTask {
186 public:
create(PassRefPtr<SQLTransaction> transaction)187     static PassOwnPtr<DeliverPendingCallbackTask> create(PassRefPtr<SQLTransaction> transaction)
188     {
189         return adoptPtr(new DeliverPendingCallbackTask(transaction));
190     }
191 
performTask(ExecutionContext *)192     virtual void performTask(ExecutionContext*)
193     {
194         m_transaction->performPendingCallback();
195     }
196 
197 private:
DeliverPendingCallbackTask(PassRefPtr<SQLTransaction> transaction)198     DeliverPendingCallbackTask(PassRefPtr<SQLTransaction> transaction)
199         : m_transaction(transaction)
200     {
201     }
202 
203     RefPtr<SQLTransaction> m_transaction;
204 };
205 
scheduleTransactionCallback(SQLTransaction * transaction)206 void Database::scheduleTransactionCallback(SQLTransaction* transaction)
207 {
208     m_executionContext->postTask(DeliverPendingCallbackTask::create(transaction));
209 }
210 
performGetTableNames()211 Vector<String> Database::performGetTableNames()
212 {
213     disableAuthorizer();
214 
215     SQLiteStatement statement(sqliteDatabase(), "SELECT name FROM sqlite_master WHERE type='table';");
216     if (statement.prepare() != SQLResultOk) {
217         WTF_LOG_ERROR("Unable to retrieve list of tables for database %s", databaseDebugName().ascii().data());
218         enableAuthorizer();
219         return Vector<String>();
220     }
221 
222     Vector<String> tableNames;
223     int result;
224     while ((result = statement.step()) == SQLResultRow) {
225         String name = statement.getColumnText(0);
226         if (name != databaseInfoTableName())
227             tableNames.append(name);
228     }
229 
230     enableAuthorizer();
231 
232     if (result != SQLResultDone) {
233         WTF_LOG_ERROR("Error getting tables for database %s", databaseDebugName().ascii().data());
234         return Vector<String>();
235     }
236 
237     return tableNames;
238 }
239 
tableNames()240 Vector<String> Database::tableNames()
241 {
242     // FIXME: Not using isolatedCopy on these strings looks ok since threads take strict turns
243     // in dealing with them. However, if the code changes, this may not be true anymore.
244     Vector<String> result;
245     DatabaseTaskSynchronizer synchronizer;
246     if (!databaseContext()->databaseThread() || databaseContext()->databaseThread()->terminationRequested(&synchronizer))
247         return result;
248 
249     OwnPtr<DatabaseTableNamesTask> task = DatabaseTableNamesTask::create(this, &synchronizer, result);
250     databaseContext()->databaseThread()->scheduleTask(task.release());
251     synchronizer.waitForTaskCompletion();
252 
253     return result;
254 }
255 
securityOrigin() const256 SecurityOrigin* Database::securityOrigin() const
257 {
258     if (m_executionContext->isContextThread())
259         return m_contextThreadSecurityOrigin.get();
260     if (databaseContext()->databaseThread()->isDatabaseThread())
261         return m_databaseThreadSecurityOrigin.get();
262     return 0;
263 }
264 
reportStartTransactionResult(int errorSite,int webSqlErrorCode,int sqliteErrorCode)265 void Database::reportStartTransactionResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode)
266 {
267     backend()->reportStartTransactionResult(errorSite, webSqlErrorCode, sqliteErrorCode);
268 }
269 
reportCommitTransactionResult(int errorSite,int webSqlErrorCode,int sqliteErrorCode)270 void Database::reportCommitTransactionResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode)
271 {
272     backend()->reportCommitTransactionResult(errorSite, webSqlErrorCode, sqliteErrorCode);
273 }
274 
275 
276 } // namespace WebCore
277