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
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
31 #include "InspectorDatabaseAgent.h"
32
33 #if ENABLE(INSPECTOR) && ENABLE(DATABASE)
34
35 #include "Database.h"
36 #include "ExceptionCode.h"
37 #include "InspectorDatabaseResource.h"
38 #include "InspectorFrontend.h"
39 #include "InspectorState.h"
40 #include "InspectorValues.h"
41 #include "InstrumentingAgents.h"
42 #include "SQLError.h"
43 #include "SQLStatementCallback.h"
44 #include "SQLStatementErrorCallback.h"
45 #include "SQLResultSetRowList.h"
46 #include "SQLTransaction.h"
47 #include "SQLTransactionCallback.h"
48 #include "SQLTransactionErrorCallback.h"
49 #include "SQLValue.h"
50 #include "VoidCallback.h"
51
52 #include <wtf/Vector.h>
53
54 namespace WebCore {
55
56 namespace DatabaseAgentState {
57 static const char databaseAgentEnabled[] = "databaseAgentEnabled";
58 };
59
60 class InspectorDatabaseAgent::FrontendProvider : public RefCounted<InspectorDatabaseAgent::FrontendProvider> {
61 public:
create(InspectorFrontend * inspectorFrontend)62 static PassRefPtr<FrontendProvider> create(InspectorFrontend* inspectorFrontend)
63 {
64 return adoptRef(new FrontendProvider(inspectorFrontend));
65 }
66
~FrontendProvider()67 virtual ~FrontendProvider() { }
68
frontend()69 InspectorFrontend::Database* frontend() { return m_inspectorFrontend; }
clearFrontend()70 void clearFrontend() { m_inspectorFrontend = 0; }
71 private:
FrontendProvider(InspectorFrontend * inspectorFrontend)72 FrontendProvider(InspectorFrontend* inspectorFrontend) : m_inspectorFrontend(inspectorFrontend->database()) { }
73 InspectorFrontend::Database* m_inspectorFrontend;
74 };
75
76 namespace {
77
78 int lastTransactionId = 0;
79
reportTransactionFailed(InspectorFrontend::Database * frontend,int transactionId,SQLError * error)80 void reportTransactionFailed(InspectorFrontend::Database* frontend, int transactionId, SQLError* error)
81 {
82 if (!frontend)
83 return;
84 RefPtr<InspectorObject> errorObject = InspectorObject::create();
85 errorObject->setString("message", error->message());
86 errorObject->setNumber("code", error->code());
87 frontend->sqlTransactionFailed(transactionId, errorObject);
88 }
89
90 class StatementCallback : public SQLStatementCallback {
91 public:
create(int transactionId,PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)92 static PassRefPtr<StatementCallback> create(int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
93 {
94 return adoptRef(new StatementCallback(transactionId, frontendProvider));
95 }
96
~StatementCallback()97 virtual ~StatementCallback() { }
98
handleEvent(SQLTransaction *,SQLResultSet * resultSet)99 virtual bool handleEvent(SQLTransaction*, SQLResultSet* resultSet)
100 {
101 if (!m_frontendProvider->frontend())
102 return true;
103
104 SQLResultSetRowList* rowList = resultSet->rows();
105
106 RefPtr<InspectorArray> columnNames = InspectorArray::create();
107 const Vector<String>& columns = rowList->columnNames();
108 for (size_t i = 0; i < columns.size(); ++i)
109 columnNames->pushString(columns[i]);
110
111 RefPtr<InspectorArray> values = InspectorArray::create();
112 const Vector<SQLValue>& data = rowList->values();
113 for (size_t i = 0; i < data.size(); ++i) {
114 const SQLValue& value = rowList->values()[i];
115 switch (value.type()) {
116 case SQLValue::StringValue: values->pushString(value.string()); break;
117 case SQLValue::NumberValue: values->pushNumber(value.number()); break;
118 case SQLValue::NullValue: values->pushValue(InspectorValue::null()); break;
119 }
120 }
121 m_frontendProvider->frontend()->sqlTransactionSucceeded(m_transactionId, columnNames, values);
122 return true;
123 }
124
125 private:
StatementCallback(int transactionId,PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)126 StatementCallback(int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
127 : m_transactionId(transactionId)
128 , m_frontendProvider(frontendProvider) { }
129 int m_transactionId;
130 RefPtr<InspectorDatabaseAgent::FrontendProvider> m_frontendProvider;
131 };
132
133 class StatementErrorCallback : public SQLStatementErrorCallback {
134 public:
create(int transactionId,PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)135 static PassRefPtr<StatementErrorCallback> create(int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
136 {
137 return adoptRef(new StatementErrorCallback(transactionId, frontendProvider));
138 }
139
~StatementErrorCallback()140 virtual ~StatementErrorCallback() { }
141
handleEvent(SQLTransaction *,SQLError * error)142 virtual bool handleEvent(SQLTransaction*, SQLError* error)
143 {
144 reportTransactionFailed(m_frontendProvider->frontend(), m_transactionId, error);
145 return true;
146 }
147
148 private:
StatementErrorCallback(int transactionId,PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)149 StatementErrorCallback(int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
150 : m_transactionId(transactionId)
151 , m_frontendProvider(frontendProvider) { }
152 int m_transactionId;
153 RefPtr<InspectorDatabaseAgent::FrontendProvider> m_frontendProvider;
154 };
155
156 class TransactionCallback : public SQLTransactionCallback {
157 public:
create(const String & sqlStatement,int transactionId,PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)158 static PassRefPtr<TransactionCallback> create(const String& sqlStatement, int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
159 {
160 return adoptRef(new TransactionCallback(sqlStatement, transactionId, frontendProvider));
161 }
162
~TransactionCallback()163 virtual ~TransactionCallback() { }
164
handleEvent(SQLTransaction * transaction)165 virtual bool handleEvent(SQLTransaction* transaction)
166 {
167 if (!m_frontendProvider->frontend())
168 return true;
169
170 Vector<SQLValue> sqlValues;
171 RefPtr<SQLStatementCallback> callback(StatementCallback::create(m_transactionId, m_frontendProvider));
172 RefPtr<SQLStatementErrorCallback> errorCallback(StatementErrorCallback::create(m_transactionId, m_frontendProvider));
173 ExceptionCode ec = 0;
174 transaction->executeSQL(m_sqlStatement, sqlValues, callback.release(), errorCallback.release(), ec);
175 return true;
176 }
177 private:
TransactionCallback(const String & sqlStatement,int transactionId,PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)178 TransactionCallback(const String& sqlStatement, int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
179 : m_sqlStatement(sqlStatement)
180 , m_transactionId(transactionId)
181 , m_frontendProvider(frontendProvider) { }
182 String m_sqlStatement;
183 int m_transactionId;
184 RefPtr<InspectorDatabaseAgent::FrontendProvider> m_frontendProvider;
185 };
186
187 class TransactionErrorCallback : public SQLTransactionErrorCallback {
188 public:
create(int transactionId,PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)189 static PassRefPtr<TransactionErrorCallback> create(int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
190 {
191 return adoptRef(new TransactionErrorCallback(transactionId, frontendProvider));
192 }
193
~TransactionErrorCallback()194 virtual ~TransactionErrorCallback() { }
195
handleEvent(SQLError * error)196 virtual bool handleEvent(SQLError* error)
197 {
198 reportTransactionFailed(m_frontendProvider->frontend(), m_transactionId, error);
199 return true;
200 }
201 private:
TransactionErrorCallback(int transactionId,PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)202 TransactionErrorCallback(int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider)
203 : m_transactionId(transactionId)
204 , m_frontendProvider(frontendProvider) { }
205 int m_transactionId;
206 RefPtr<InspectorDatabaseAgent::FrontendProvider> m_frontendProvider;
207 };
208
209 class TransactionSuccessCallback : public VoidCallback {
210 public:
create()211 static PassRefPtr<TransactionSuccessCallback> create()
212 {
213 return adoptRef(new TransactionSuccessCallback());
214 }
215
~TransactionSuccessCallback()216 virtual ~TransactionSuccessCallback() { }
217
handleEvent()218 virtual void handleEvent() { }
219
220 private:
TransactionSuccessCallback()221 TransactionSuccessCallback() { }
222 };
223
224 } // namespace
225
didOpenDatabase(PassRefPtr<Database> database,const String & domain,const String & name,const String & version)226 void InspectorDatabaseAgent::didOpenDatabase(PassRefPtr<Database> database, const String& domain, const String& name, const String& version)
227 {
228 if (InspectorDatabaseResource* resource = findByFileName(database->fileName())) {
229 resource->setDatabase(database);
230 return;
231 }
232
233 RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version);
234 m_resources.set(resource->id(), resource);
235 // Resources are only bound while visible.
236 if (m_frontendProvider && m_enabled)
237 resource->bind(m_frontendProvider->frontend());
238 }
239
clearResources()240 void InspectorDatabaseAgent::clearResources()
241 {
242 m_resources.clear();
243 }
244
InspectorDatabaseAgent(InstrumentingAgents * instrumentingAgents,InspectorState * state)245 InspectorDatabaseAgent::InspectorDatabaseAgent(InstrumentingAgents* instrumentingAgents, InspectorState* state)
246 : m_instrumentingAgents(instrumentingAgents)
247 , m_inspectorState(state)
248 , m_enabled(false)
249 {
250 m_instrumentingAgents->setInspectorDatabaseAgent(this);
251 }
252
~InspectorDatabaseAgent()253 InspectorDatabaseAgent::~InspectorDatabaseAgent()
254 {
255 m_instrumentingAgents->setInspectorDatabaseAgent(0);
256 }
257
setFrontend(InspectorFrontend * frontend)258 void InspectorDatabaseAgent::setFrontend(InspectorFrontend* frontend)
259 {
260 m_frontendProvider = FrontendProvider::create(frontend);
261 }
262
clearFrontend()263 void InspectorDatabaseAgent::clearFrontend()
264 {
265 m_frontendProvider->clearFrontend();
266 m_frontendProvider.clear();
267 disable(0);
268 }
269
enable(ErrorString *)270 void InspectorDatabaseAgent::enable(ErrorString*)
271 {
272 if (m_enabled)
273 return;
274 m_enabled = true;
275 m_inspectorState->setBoolean(DatabaseAgentState::databaseAgentEnabled, m_enabled);
276
277 DatabaseResourcesMap::iterator databasesEnd = m_resources.end();
278 for (DatabaseResourcesMap::iterator it = m_resources.begin(); it != databasesEnd; ++it)
279 it->second->bind(m_frontendProvider->frontend());
280 }
281
disable(ErrorString *)282 void InspectorDatabaseAgent::disable(ErrorString*)
283 {
284 if (!m_enabled)
285 return;
286 m_enabled = false;
287 m_inspectorState->setBoolean(DatabaseAgentState::databaseAgentEnabled, m_enabled);
288 }
289
restore()290 void InspectorDatabaseAgent::restore()
291 {
292 m_enabled = m_inspectorState->getBoolean(DatabaseAgentState::databaseAgentEnabled);
293 }
294
getDatabaseTableNames(ErrorString * error,int databaseId,RefPtr<InspectorArray> * names)295 void InspectorDatabaseAgent::getDatabaseTableNames(ErrorString* error, int databaseId, RefPtr<InspectorArray>* names)
296 {
297 if (!m_enabled) {
298 *error = "Database agent is not enabled";
299 return;
300 }
301
302 Database* database = databaseForId(databaseId);
303 if (database) {
304 Vector<String> tableNames = database->tableNames();
305 unsigned length = tableNames.size();
306 for (unsigned i = 0; i < length; ++i)
307 (*names)->pushString(tableNames[i]);
308 }
309 }
310
executeSQL(ErrorString * error,int databaseId,const String & query,bool * success,int * transactionId)311 void InspectorDatabaseAgent::executeSQL(ErrorString* error, int databaseId, const String& query, bool* success, int* transactionId)
312 {
313 if (!m_enabled) {
314 *error = "Database agent is not enabled";
315 return;
316 }
317
318 Database* database = databaseForId(databaseId);
319 if (!database) {
320 *success = false;
321 return;
322 }
323
324 *transactionId = ++lastTransactionId;
325 RefPtr<SQLTransactionCallback> callback(TransactionCallback::create(query, *transactionId, m_frontendProvider));
326 RefPtr<SQLTransactionErrorCallback> errorCallback(TransactionErrorCallback::create(*transactionId, m_frontendProvider));
327 RefPtr<VoidCallback> successCallback(TransactionSuccessCallback::create());
328 database->transaction(callback.release(), errorCallback.release(), successCallback.release());
329 *success = true;
330 }
331
databaseId(Database * database)332 int InspectorDatabaseAgent::databaseId(Database* database)
333 {
334 for (DatabaseResourcesMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) {
335 if (it->second->database() == database)
336 return it->first;
337 }
338 return 0;
339 }
340
findByFileName(const String & fileName)341 InspectorDatabaseResource* InspectorDatabaseAgent::findByFileName(const String& fileName)
342 {
343 for (DatabaseResourcesMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) {
344 if (it->second->database()->fileName() == fileName)
345 return it->second.get();
346 }
347 return 0;
348 }
349
databaseForId(int databaseId)350 Database* InspectorDatabaseAgent::databaseForId(int databaseId)
351 {
352 DatabaseResourcesMap::iterator it = m_resources.find(databaseId);
353 if (it == m_resources.end())
354 return 0;
355 return it->second->database();
356 }
357
358 } // namespace WebCore
359
360 #endif // ENABLE(INSPECTOR) && ENABLE(DATABASE)
361