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