1 /* 2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. 3 * Copyright (C) 2007 Justin Haygood (jhaygood (at) reaktix.com) 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 #include "modules/webdatabase/sqlite/SQLiteDatabase.h" 29 30 #include <sqlite3.h> 31 #include "platform/Logging.h" 32 #include "modules/webdatabase/sqlite/SQLiteFileSystem.h" 33 #include "modules/webdatabase/sqlite/SQLiteStatement.h" 34 #include "modules/webdatabase/DatabaseAuthorizer.h" 35 36 namespace blink { 37 38 const int SQLResultDone = SQLITE_DONE; 39 const int SQLResultOk = SQLITE_OK; 40 const int SQLResultRow = SQLITE_ROW; 41 const int SQLResultFull = SQLITE_FULL; 42 const int SQLResultInterrupt = SQLITE_INTERRUPT; 43 const int SQLResultConstraint = SQLITE_CONSTRAINT; 44 45 static const char notOpenErrorMessage[] = "database is not open"; 46 47 SQLiteDatabase::SQLiteDatabase() 48 : m_db(0) 49 , m_pageSize(-1) 50 , m_transactionInProgress(false) 51 , m_sharable(false) 52 , m_openingThread(0) 53 , m_openError(SQLITE_ERROR) 54 , m_openErrorMessage() 55 , m_lastChangesCount(0) 56 { 57 } 58 59 SQLiteDatabase::~SQLiteDatabase() 60 { 61 close(); 62 } 63 64 bool SQLiteDatabase::open(const String& filename, bool forWebSQLDatabase) 65 { 66 close(); 67 68 m_openError = SQLiteFileSystem::openDatabase(filename, &m_db, forWebSQLDatabase); 69 if (m_openError != SQLITE_OK) { 70 m_openErrorMessage = m_db ? sqlite3_errmsg(m_db) : "sqlite_open returned null"; 71 WTF_LOG_ERROR("SQLite database failed to load from %s\nCause - %s", filename.ascii().data(), 72 m_openErrorMessage.data()); 73 sqlite3_close(m_db); 74 m_db = 0; 75 return false; 76 } 77 78 m_openError = sqlite3_extended_result_codes(m_db, 1); 79 if (m_openError != SQLITE_OK) { 80 m_openErrorMessage = sqlite3_errmsg(m_db); 81 WTF_LOG_ERROR("SQLite database error when enabling extended errors - %s", m_openErrorMessage.data()); 82 sqlite3_close(m_db); 83 m_db = 0; 84 return false; 85 } 86 87 if (isOpen()) 88 m_openingThread = currentThread(); 89 else 90 m_openErrorMessage = "sqlite_open returned null"; 91 92 if (!SQLiteStatement(*this, "PRAGMA temp_store = MEMORY;").executeCommand()) 93 WTF_LOG_ERROR("SQLite database could not set temp_store to memory"); 94 95 return isOpen(); 96 } 97 98 void SQLiteDatabase::close() 99 { 100 if (m_db) { 101 // FIXME: This is being called on the main thread during JS GC. <rdar://problem/5739818> 102 // ASSERT(currentThread() == m_openingThread); 103 sqlite3* db = m_db; 104 { 105 MutexLocker locker(m_databaseClosingMutex); 106 m_db = 0; 107 } 108 sqlite3_close(db); 109 } 110 111 m_openingThread = 0; 112 m_openError = SQLITE_ERROR; 113 m_openErrorMessage = CString(); 114 } 115 116 void SQLiteDatabase::setMaximumSize(int64_t size) 117 { 118 if (size < 0) 119 size = 0; 120 121 int currentPageSize = pageSize(); 122 123 ASSERT(currentPageSize || !m_db); 124 int64_t newMaxPageCount = currentPageSize ? size / currentPageSize : 0; 125 126 MutexLocker locker(m_authorizerLock); 127 enableAuthorizer(false); 128 129 SQLiteStatement statement(*this, "PRAGMA max_page_count = " + String::number(newMaxPageCount)); 130 statement.prepare(); 131 if (statement.step() != SQLResultRow) 132 #if OS(WIN) 133 WTF_LOG_ERROR("Failed to set maximum size of database to %I64i bytes", static_cast<long long>(size)); 134 #else 135 WTF_LOG_ERROR("Failed to set maximum size of database to %lli bytes", static_cast<long long>(size)); 136 #endif 137 138 enableAuthorizer(true); 139 140 } 141 142 int SQLiteDatabase::pageSize() 143 { 144 // Since the page size of a database is locked in at creation and therefore cannot be dynamic, 145 // we can cache the value for future use 146 if (m_pageSize == -1) { 147 MutexLocker locker(m_authorizerLock); 148 enableAuthorizer(false); 149 150 SQLiteStatement statement(*this, "PRAGMA page_size"); 151 m_pageSize = statement.getColumnInt(0); 152 153 enableAuthorizer(true); 154 } 155 156 return m_pageSize; 157 } 158 159 int64_t SQLiteDatabase::freeSpaceSize() 160 { 161 int64_t freelistCount = 0; 162 163 { 164 MutexLocker locker(m_authorizerLock); 165 enableAuthorizer(false); 166 // Note: freelist_count was added in SQLite 3.4.1. 167 SQLiteStatement statement(*this, "PRAGMA freelist_count"); 168 freelistCount = statement.getColumnInt64(0); 169 enableAuthorizer(true); 170 } 171 172 return freelistCount * pageSize(); 173 } 174 175 int64_t SQLiteDatabase::totalSize() 176 { 177 int64_t pageCount = 0; 178 179 { 180 MutexLocker locker(m_authorizerLock); 181 enableAuthorizer(false); 182 SQLiteStatement statement(*this, "PRAGMA page_count"); 183 pageCount = statement.getColumnInt64(0); 184 enableAuthorizer(true); 185 } 186 187 return pageCount * pageSize(); 188 } 189 190 void SQLiteDatabase::setBusyTimeout(int ms) 191 { 192 if (m_db) 193 sqlite3_busy_timeout(m_db, ms); 194 else 195 WTF_LOG(SQLDatabase, "BusyTimeout set on non-open database"); 196 } 197 198 bool SQLiteDatabase::executeCommand(const String& sql) 199 { 200 return SQLiteStatement(*this, sql).executeCommand(); 201 } 202 203 bool SQLiteDatabase::tableExists(const String& tablename) 204 { 205 if (!isOpen()) 206 return false; 207 208 String statement = "SELECT name FROM sqlite_master WHERE type = 'table' AND name = '" + tablename + "';"; 209 210 SQLiteStatement sql(*this, statement); 211 sql.prepare(); 212 return sql.step() == SQLITE_ROW; 213 } 214 215 int SQLiteDatabase::runVacuumCommand() 216 { 217 if (!executeCommand("VACUUM;")) 218 WTF_LOG(SQLDatabase, "Unable to vacuum database - %s", lastErrorMsg()); 219 return lastError(); 220 } 221 222 int SQLiteDatabase::runIncrementalVacuumCommand() 223 { 224 MutexLocker locker(m_authorizerLock); 225 enableAuthorizer(false); 226 227 if (!executeCommand("PRAGMA incremental_vacuum")) 228 WTF_LOG(SQLDatabase, "Unable to run incremental vacuum - %s", lastErrorMsg()); 229 230 enableAuthorizer(true); 231 return lastError(); 232 } 233 234 int64_t SQLiteDatabase::lastInsertRowID() 235 { 236 if (!m_db) 237 return 0; 238 return sqlite3_last_insert_rowid(m_db); 239 } 240 241 void SQLiteDatabase::updateLastChangesCount() 242 { 243 if (!m_db) 244 return; 245 246 m_lastChangesCount = sqlite3_total_changes(m_db); 247 } 248 249 int SQLiteDatabase::lastChanges() 250 { 251 if (!m_db) 252 return 0; 253 254 return sqlite3_total_changes(m_db) - m_lastChangesCount; 255 } 256 257 int SQLiteDatabase::lastError() 258 { 259 return m_db ? sqlite3_errcode(m_db) : m_openError; 260 } 261 262 const char* SQLiteDatabase::lastErrorMsg() 263 { 264 if (m_db) 265 return sqlite3_errmsg(m_db); 266 return m_openErrorMessage.isNull() ? notOpenErrorMessage : m_openErrorMessage.data(); 267 } 268 269 int SQLiteDatabase::authorizerFunction(void* userData, int actionCode, const char* parameter1, const char* parameter2, const char* /*databaseName*/, const char* /*trigger_or_view*/) 270 { 271 DatabaseAuthorizer* auth = static_cast<DatabaseAuthorizer*>(userData); 272 ASSERT(auth); 273 274 switch (actionCode) { 275 case SQLITE_CREATE_INDEX: 276 return auth->createIndex(parameter1, parameter2); 277 case SQLITE_CREATE_TABLE: 278 return auth->createTable(parameter1); 279 case SQLITE_CREATE_TEMP_INDEX: 280 return auth->createTempIndex(parameter1, parameter2); 281 case SQLITE_CREATE_TEMP_TABLE: 282 return auth->createTempTable(parameter1); 283 case SQLITE_CREATE_TEMP_TRIGGER: 284 return auth->createTempTrigger(parameter1, parameter2); 285 case SQLITE_CREATE_TEMP_VIEW: 286 return auth->createTempView(parameter1); 287 case SQLITE_CREATE_TRIGGER: 288 return auth->createTrigger(parameter1, parameter2); 289 case SQLITE_CREATE_VIEW: 290 return auth->createView(parameter1); 291 case SQLITE_DELETE: 292 return auth->allowDelete(parameter1); 293 case SQLITE_DROP_INDEX: 294 return auth->dropIndex(parameter1, parameter2); 295 case SQLITE_DROP_TABLE: 296 return auth->dropTable(parameter1); 297 case SQLITE_DROP_TEMP_INDEX: 298 return auth->dropTempIndex(parameter1, parameter2); 299 case SQLITE_DROP_TEMP_TABLE: 300 return auth->dropTempTable(parameter1); 301 case SQLITE_DROP_TEMP_TRIGGER: 302 return auth->dropTempTrigger(parameter1, parameter2); 303 case SQLITE_DROP_TEMP_VIEW: 304 return auth->dropTempView(parameter1); 305 case SQLITE_DROP_TRIGGER: 306 return auth->dropTrigger(parameter1, parameter2); 307 case SQLITE_DROP_VIEW: 308 return auth->dropView(parameter1); 309 case SQLITE_INSERT: 310 return auth->allowInsert(parameter1); 311 case SQLITE_PRAGMA: 312 return auth->allowPragma(parameter1, parameter2); 313 case SQLITE_READ: 314 return auth->allowRead(parameter1, parameter2); 315 case SQLITE_SELECT: 316 return auth->allowSelect(); 317 case SQLITE_TRANSACTION: 318 return auth->allowTransaction(); 319 case SQLITE_UPDATE: 320 return auth->allowUpdate(parameter1, parameter2); 321 case SQLITE_ATTACH: 322 return auth->allowAttach(parameter1); 323 case SQLITE_DETACH: 324 return auth->allowDetach(parameter1); 325 case SQLITE_ALTER_TABLE: 326 return auth->allowAlterTable(parameter1, parameter2); 327 case SQLITE_REINDEX: 328 return auth->allowReindex(parameter1); 329 #if SQLITE_VERSION_NUMBER >= 3003013 330 case SQLITE_ANALYZE: 331 return auth->allowAnalyze(parameter1); 332 case SQLITE_CREATE_VTABLE: 333 return auth->createVTable(parameter1, parameter2); 334 case SQLITE_DROP_VTABLE: 335 return auth->dropVTable(parameter1, parameter2); 336 case SQLITE_FUNCTION: 337 return auth->allowFunction(parameter2); 338 #endif 339 default: 340 ASSERT_NOT_REACHED(); 341 return SQLAuthDeny; 342 } 343 } 344 345 void SQLiteDatabase::setAuthorizer(DatabaseAuthorizer* auth) 346 { 347 if (!m_db) { 348 WTF_LOG_ERROR("Attempt to set an authorizer on a non-open SQL database"); 349 ASSERT_NOT_REACHED(); 350 return; 351 } 352 353 MutexLocker locker(m_authorizerLock); 354 355 m_authorizer = auth; 356 357 enableAuthorizer(true); 358 } 359 360 void SQLiteDatabase::enableAuthorizer(bool enable) 361 { 362 if (m_authorizer && enable) 363 sqlite3_set_authorizer(m_db, SQLiteDatabase::authorizerFunction, m_authorizer.get()); 364 else 365 sqlite3_set_authorizer(m_db, NULL, 0); 366 } 367 368 bool SQLiteDatabase::isAutoCommitOn() const 369 { 370 return sqlite3_get_autocommit(m_db); 371 } 372 373 bool SQLiteDatabase::turnOnIncrementalAutoVacuum() 374 { 375 SQLiteStatement statement(*this, "PRAGMA auto_vacuum"); 376 int autoVacuumMode = statement.getColumnInt(0); 377 int error = lastError(); 378 379 // Check if we got an error while trying to get the value of the auto_vacuum flag. 380 // If we got a SQLITE_BUSY error, then there's probably another transaction in 381 // progress on this database. In this case, keep the current value of the 382 // auto_vacuum flag and try to set it to INCREMENTAL the next time we open this 383 // database. If the error is not SQLITE_BUSY, then we probably ran into a more 384 // serious problem and should return false (to log an error message). 385 if (error != SQLITE_ROW) 386 return false; 387 388 switch (autoVacuumMode) { 389 case AutoVacuumIncremental: 390 return true; 391 case AutoVacuumFull: 392 return executeCommand("PRAGMA auto_vacuum = 2"); 393 case AutoVacuumNone: 394 default: 395 if (!executeCommand("PRAGMA auto_vacuum = 2")) 396 return false; 397 runVacuumCommand(); 398 error = lastError(); 399 return (error == SQLITE_OK); 400 } 401 } 402 403 void SQLiteDatabase::trace(Visitor* visitor) 404 { 405 visitor->trace(m_authorizer); 406 } 407 408 } // namespace blink 409