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 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#if ENABLE(INSPECTOR) && ENABLE(SQL_DATABASE) 32 33#include "InspectorDatabaseAgent.h" 34 35#include "Database.h" 36#include "ExceptionCode.h" 37#include "ExceptionCodePlaceholder.h" 38#include "InspectorDatabaseResource.h" 39#include "InspectorWebFrontendDispatchers.h" 40#include "InstrumentingAgents.h" 41#include "SQLError.h" 42#include "SQLResultSet.h" 43#include "SQLResultSetRowList.h" 44#include "SQLStatementCallback.h" 45#include "SQLStatementErrorCallback.h" 46#include "SQLTransaction.h" 47#include "SQLTransactionCallback.h" 48#include "SQLTransactionErrorCallback.h" 49#include "SQLValue.h" 50#include "VoidCallback.h" 51#include <inspector/InspectorValues.h> 52#include <wtf/Vector.h> 53 54typedef Inspector::InspectorDatabaseBackendDispatcherHandler::ExecuteSQLCallback ExecuteSQLCallback; 55 56using namespace Inspector; 57 58namespace WebCore { 59 60namespace { 61 62void reportTransactionFailed(ExecuteSQLCallback* requestCallback, SQLError* error) 63{ 64 RefPtr<Inspector::TypeBuilder::Database::Error> errorObject = Inspector::TypeBuilder::Database::Error::create() 65 .setMessage(error->message()) 66 .setCode(error->code()); 67 requestCallback->sendSuccess(nullptr, nullptr, errorObject.release()); 68} 69 70class StatementCallback : public SQLStatementCallback { 71public: 72 static PassRefPtr<StatementCallback> create(PassRefPtr<ExecuteSQLCallback> requestCallback) 73 { 74 return adoptRef(new StatementCallback(requestCallback)); 75 } 76 77 virtual ~StatementCallback() { } 78 79 virtual bool handleEvent(SQLTransaction*, SQLResultSet* resultSet) override 80 { 81 SQLResultSetRowList* rowList = resultSet->rows(); 82 83 RefPtr<Inspector::TypeBuilder::Array<String>> columnNames = Inspector::TypeBuilder::Array<String>::create(); 84 const Vector<String>& columns = rowList->columnNames(); 85 for (size_t i = 0; i < columns.size(); ++i) 86 columnNames->addItem(columns[i]); 87 88 RefPtr<Inspector::TypeBuilder::Array<InspectorValue>> values = Inspector::TypeBuilder::Array<InspectorValue>::create(); 89 const Vector<SQLValue>& data = rowList->values(); 90 for (size_t i = 0; i < data.size(); ++i) { 91 const SQLValue& value = rowList->values()[i]; 92 switch (value.type()) { 93 case SQLValue::StringValue: values->addItem(InspectorString::create(value.string())); break; 94 case SQLValue::NumberValue: values->addItem(InspectorBasicValue::create(value.number())); break; 95 case SQLValue::NullValue: values->addItem(InspectorValue::null()); break; 96 } 97 } 98 m_requestCallback->sendSuccess(columnNames.release(), values.release(), nullptr); 99 return true; 100 } 101 102private: 103 StatementCallback(PassRefPtr<ExecuteSQLCallback> requestCallback) 104 : m_requestCallback(requestCallback) { } 105 RefPtr<ExecuteSQLCallback> m_requestCallback; 106}; 107 108class StatementErrorCallback : public SQLStatementErrorCallback { 109public: 110 static PassRefPtr<StatementErrorCallback> create(PassRefPtr<ExecuteSQLCallback> requestCallback) 111 { 112 return adoptRef(new StatementErrorCallback(requestCallback)); 113 } 114 115 virtual ~StatementErrorCallback() { } 116 117 virtual bool handleEvent(SQLTransaction*, SQLError* error) override 118 { 119 reportTransactionFailed(m_requestCallback.get(), error); 120 return true; 121 } 122 123private: 124 StatementErrorCallback(PassRefPtr<ExecuteSQLCallback> requestCallback) 125 : m_requestCallback(requestCallback) { } 126 RefPtr<ExecuteSQLCallback> m_requestCallback; 127}; 128 129class TransactionCallback : public SQLTransactionCallback { 130public: 131 static PassRefPtr<TransactionCallback> create(const String& sqlStatement, PassRefPtr<ExecuteSQLCallback> requestCallback) 132 { 133 return adoptRef(new TransactionCallback(sqlStatement, requestCallback)); 134 } 135 136 virtual ~TransactionCallback() { } 137 138 virtual bool handleEvent(SQLTransaction* transaction) override 139 { 140 if (!m_requestCallback->isActive()) 141 return true; 142 143 Vector<SQLValue> sqlValues; 144 RefPtr<SQLStatementCallback> callback(StatementCallback::create(m_requestCallback.get())); 145 RefPtr<SQLStatementErrorCallback> errorCallback(StatementErrorCallback::create(m_requestCallback.get())); 146 transaction->executeSQL(m_sqlStatement, sqlValues, callback.release(), errorCallback.release(), IGNORE_EXCEPTION); 147 return true; 148 } 149private: 150 TransactionCallback(const String& sqlStatement, PassRefPtr<ExecuteSQLCallback> requestCallback) 151 : m_sqlStatement(sqlStatement) 152 , m_requestCallback(requestCallback) { } 153 String m_sqlStatement; 154 RefPtr<ExecuteSQLCallback> m_requestCallback; 155}; 156 157class TransactionErrorCallback : public SQLTransactionErrorCallback { 158public: 159 static PassRefPtr<TransactionErrorCallback> create(PassRefPtr<ExecuteSQLCallback> requestCallback) 160 { 161 return adoptRef(new TransactionErrorCallback(requestCallback)); 162 } 163 164 virtual ~TransactionErrorCallback() { } 165 166 virtual bool handleEvent(SQLError* error) override 167 { 168 reportTransactionFailed(m_requestCallback.get(), error); 169 return true; 170 } 171private: 172 TransactionErrorCallback(PassRefPtr<ExecuteSQLCallback> requestCallback) 173 : m_requestCallback(requestCallback) { } 174 RefPtr<ExecuteSQLCallback> m_requestCallback; 175}; 176 177class TransactionSuccessCallback : public VoidCallback { 178public: 179 static PassRefPtr<TransactionSuccessCallback> create() 180 { 181 return adoptRef(new TransactionSuccessCallback()); 182 } 183 184 virtual ~TransactionSuccessCallback() { } 185 186 virtual bool handleEvent() override { return false; } 187 188private: 189 TransactionSuccessCallback() { } 190}; 191 192} // namespace 193 194void InspectorDatabaseAgent::didOpenDatabase(PassRefPtr<Database> database, const String& domain, const String& name, const String& version) 195{ 196 if (InspectorDatabaseResource* resource = findByFileName(database->fileName())) { 197 resource->setDatabase(database); 198 return; 199 } 200 201 RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version); 202 m_resources.set(resource->id(), resource); 203 // Resources are only bound while visible. 204 if (m_frontendDispatcher && m_enabled) 205 resource->bind(m_frontendDispatcher.get()); 206} 207 208void InspectorDatabaseAgent::clearResources() 209{ 210 m_resources.clear(); 211} 212 213InspectorDatabaseAgent::InspectorDatabaseAgent(InstrumentingAgents* instrumentingAgents) 214 : InspectorAgentBase(ASCIILiteral("Database"), instrumentingAgents) 215 , m_enabled(false) 216{ 217 m_instrumentingAgents->setInspectorDatabaseAgent(this); 218} 219 220InspectorDatabaseAgent::~InspectorDatabaseAgent() 221{ 222 m_instrumentingAgents->setInspectorDatabaseAgent(nullptr); 223} 224 225void InspectorDatabaseAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher) 226{ 227 m_frontendDispatcher = std::make_unique<InspectorDatabaseFrontendDispatcher>(frontendChannel); 228 m_backendDispatcher = InspectorDatabaseBackendDispatcher::create(backendDispatcher, this); 229} 230 231void InspectorDatabaseAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason) 232{ 233 m_frontendDispatcher = nullptr; 234 m_backendDispatcher.clear(); 235 236 disable(nullptr); 237} 238 239void InspectorDatabaseAgent::enable(ErrorString*) 240{ 241 if (m_enabled) 242 return; 243 m_enabled = true; 244 245 DatabaseResourcesMap::iterator databasesEnd = m_resources.end(); 246 for (DatabaseResourcesMap::iterator it = m_resources.begin(); it != databasesEnd; ++it) 247 it->value->bind(m_frontendDispatcher.get()); 248} 249 250void InspectorDatabaseAgent::disable(ErrorString*) 251{ 252 if (!m_enabled) 253 return; 254 m_enabled = false; 255} 256 257void InspectorDatabaseAgent::getDatabaseTableNames(ErrorString* error, const String& databaseId, RefPtr<Inspector::TypeBuilder::Array<String>>& names) 258{ 259 if (!m_enabled) { 260 *error = "Database agent is not enabled"; 261 return; 262 } 263 264 names = Inspector::TypeBuilder::Array<String>::create(); 265 266 Database* database = databaseForId(databaseId); 267 if (database) { 268 Vector<String> tableNames = database->tableNames(); 269 unsigned length = tableNames.size(); 270 for (unsigned i = 0; i < length; ++i) 271 names->addItem(tableNames[i]); 272 } 273} 274 275void InspectorDatabaseAgent::executeSQL(ErrorString*, const String& databaseId, const String& query, PassRefPtr<ExecuteSQLCallback> prpRequestCallback) 276{ 277 RefPtr<ExecuteSQLCallback> requestCallback = prpRequestCallback; 278 279 if (!m_enabled) { 280 requestCallback->sendFailure("Database agent is not enabled"); 281 return; 282 } 283 284 Database* database = databaseForId(databaseId); 285 if (!database) { 286 requestCallback->sendFailure("Database not found"); 287 return; 288 } 289 290 RefPtr<SQLTransactionCallback> callback(TransactionCallback::create(query, requestCallback.get())); 291 RefPtr<SQLTransactionErrorCallback> errorCallback(TransactionErrorCallback::create(requestCallback.get())); 292 RefPtr<VoidCallback> successCallback(TransactionSuccessCallback::create()); 293 database->transaction(callback.release(), errorCallback.release(), successCallback.release()); 294} 295 296String InspectorDatabaseAgent::databaseId(Database* database) 297{ 298 for (DatabaseResourcesMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) { 299 if (it->value->database() == database) 300 return it->key; 301 } 302 return String(); 303} 304 305InspectorDatabaseResource* InspectorDatabaseAgent::findByFileName(const String& fileName) 306{ 307 for (DatabaseResourcesMap::iterator it = m_resources.begin(); it != m_resources.end(); ++it) { 308 if (it->value->database()->fileName() == fileName) 309 return it->value.get(); 310 } 311 return nullptr; 312} 313 314Database* InspectorDatabaseAgent::databaseForId(const String& databaseId) 315{ 316 DatabaseResourcesMap::iterator it = m_resources.find(databaseId); 317 if (it == m_resources.end()) 318 return nullptr; 319 return it->value->database(); 320} 321 322} // namespace WebCore 323 324#endif // ENABLE(INSPECTOR) && ENABLE(SQL_DATABASE) 325