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: 62 static PassRefPtr<FrontendProvider> create(InspectorFrontend* inspectorFrontend) 63 { 64 return adoptRef(new FrontendProvider(inspectorFrontend)); 65 } 66 67 virtual ~FrontendProvider() { } 68 69 InspectorFrontend::Database* frontend() { return m_inspectorFrontend; } 70 void clearFrontend() { m_inspectorFrontend = 0; } 71 private: 72 FrontendProvider(InspectorFrontend* inspectorFrontend) : m_inspectorFrontend(inspectorFrontend->database()) { } 73 InspectorFrontend::Database* m_inspectorFrontend; 74 }; 75 76 namespace { 77 78 int lastTransactionId = 0; 79 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: 92 static PassRefPtr<StatementCallback> create(int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider) 93 { 94 return adoptRef(new StatementCallback(transactionId, frontendProvider)); 95 } 96 97 virtual ~StatementCallback() { } 98 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: 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: 135 static PassRefPtr<StatementErrorCallback> create(int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider) 136 { 137 return adoptRef(new StatementErrorCallback(transactionId, frontendProvider)); 138 } 139 140 virtual ~StatementErrorCallback() { } 141 142 virtual bool handleEvent(SQLTransaction*, SQLError* error) 143 { 144 reportTransactionFailed(m_frontendProvider->frontend(), m_transactionId, error); 145 return true; 146 } 147 148 private: 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: 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 163 virtual ~TransactionCallback() { } 164 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: 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: 189 static PassRefPtr<TransactionErrorCallback> create(int transactionId, PassRefPtr<InspectorDatabaseAgent::FrontendProvider> frontendProvider) 190 { 191 return adoptRef(new TransactionErrorCallback(transactionId, frontendProvider)); 192 } 193 194 virtual ~TransactionErrorCallback() { } 195 196 virtual bool handleEvent(SQLError* error) 197 { 198 reportTransactionFailed(m_frontendProvider->frontend(), m_transactionId, error); 199 return true; 200 } 201 private: 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: 211 static PassRefPtr<TransactionSuccessCallback> create() 212 { 213 return adoptRef(new TransactionSuccessCallback()); 214 } 215 216 virtual ~TransactionSuccessCallback() { } 217 218 virtual void handleEvent() { } 219 220 private: 221 TransactionSuccessCallback() { } 222 }; 223 224 } // namespace 225 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 240 void InspectorDatabaseAgent::clearResources() 241 { 242 m_resources.clear(); 243 } 244 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 253 InspectorDatabaseAgent::~InspectorDatabaseAgent() 254 { 255 m_instrumentingAgents->setInspectorDatabaseAgent(0); 256 } 257 258 void InspectorDatabaseAgent::setFrontend(InspectorFrontend* frontend) 259 { 260 m_frontendProvider = FrontendProvider::create(frontend); 261 } 262 263 void InspectorDatabaseAgent::clearFrontend() 264 { 265 m_frontendProvider->clearFrontend(); 266 m_frontendProvider.clear(); 267 disable(0); 268 } 269 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 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 290 void InspectorDatabaseAgent::restore() 291 { 292 m_enabled = m_inspectorState->getBoolean(DatabaseAgentState::databaseAgentEnabled); 293 } 294 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 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 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 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 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