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 "SQLiteDatabase.h" 29 30 #if ENABLE(DATABASE) 31 #include "DatabaseAuthorizer.h" 32 #include "Logging.h" 33 #include "SQLiteFileSystem.h" 34 #include "SQLiteStatement.h" 35 #include <sqlite3.h> 36 #include <wtf/Threading.h> 37 #include <wtf/text/CString.h> 38 #include <wtf/text/StringConcatenate.h> 39 40 namespace WebCore { 41 42 const int SQLResultDone = SQLITE_DONE; 43 const int SQLResultError = SQLITE_ERROR; 44 const int SQLResultOk = SQLITE_OK; 45 const int SQLResultRow = SQLITE_ROW; 46 const int SQLResultSchema = SQLITE_SCHEMA; 47 const int SQLResultFull = SQLITE_FULL; 48 const int SQLResultInterrupt = SQLITE_INTERRUPT; 49 50 SQLiteDatabase::SQLiteDatabase() 51 : m_db(0) 52 , m_pageSize(-1) 53 , m_transactionInProgress(false) 54 , m_sharable(false) 55 , m_openingThread(0) 56 , m_interrupted(false) 57 { 58 } 59 60 SQLiteDatabase::~SQLiteDatabase() 61 { 62 close(); 63 } 64 65 bool SQLiteDatabase::open(const String& filename, bool forWebSQLDatabase) 66 { 67 close(); 68 69 if (SQLiteFileSystem::openDatabase(filename, &m_db, forWebSQLDatabase) != SQLITE_OK) { 70 LOG_ERROR("SQLite database failed to load from %s\nCause - %s", filename.ascii().data(), 71 sqlite3_errmsg(m_db)); 72 sqlite3_close(m_db); 73 m_db = 0; 74 return false; 75 } 76 if (sqlite3_extended_result_codes(m_db, 1) != SQLITE_OK) { 77 LOG_ERROR("SQLite database error when enabling extended errors - %s", sqlite3_errmsg(m_db)); 78 sqlite3_close(m_db); 79 m_db = 0; 80 return false; 81 } 82 83 if (isOpen()) 84 m_openingThread = currentThread(); 85 86 if (!SQLiteStatement(*this, "PRAGMA temp_store = MEMORY;").executeCommand()) 87 LOG_ERROR("SQLite database could not set temp_store to memory"); 88 89 return isOpen(); 90 } 91 92 void SQLiteDatabase::close() 93 { 94 if (m_db) { 95 // FIXME: This is being called on themain thread during JS GC. <rdar://problem/5739818> 96 // ASSERT(currentThread() == m_openingThread); 97 sqlite3* db = m_db; 98 { 99 MutexLocker locker(m_databaseClosingMutex); 100 m_db = 0; 101 } 102 sqlite3_close(db); 103 } 104 105 m_openingThread = 0; 106 } 107 108 void SQLiteDatabase::interrupt() 109 { 110 #if !ENABLE(SINGLE_THREADED) 111 m_interrupted = true; 112 while (!m_lockingMutex.tryLock()) { 113 MutexLocker locker(m_databaseClosingMutex); 114 if (!m_db) 115 return; 116 sqlite3_interrupt(m_db); 117 yield(); 118 } 119 120 m_lockingMutex.unlock(); 121 #endif 122 } 123 124 bool SQLiteDatabase::isInterrupted() 125 { 126 ASSERT(!m_lockingMutex.tryLock()); 127 return m_interrupted; 128 } 129 130 void SQLiteDatabase::setFullsync(bool fsync) 131 { 132 if (fsync) 133 executeCommand("PRAGMA fullfsync = 1;"); 134 else 135 executeCommand("PRAGMA fullfsync = 0;"); 136 } 137 138 int64_t SQLiteDatabase::maximumSize() 139 { 140 int64_t maxPageCount = 0; 141 142 { 143 MutexLocker locker(m_authorizerLock); 144 enableAuthorizer(false); 145 SQLiteStatement statement(*this, "PRAGMA max_page_count"); 146 maxPageCount = statement.getColumnInt64(0); 147 enableAuthorizer(true); 148 } 149 150 return maxPageCount * pageSize(); 151 } 152 153 void SQLiteDatabase::setMaximumSize(int64_t size) 154 { 155 if (size < 0) 156 size = 0; 157 158 int currentPageSize = pageSize(); 159 160 ASSERT(currentPageSize); 161 int64_t newMaxPageCount = currentPageSize ? size / currentPageSize : 0; 162 163 MutexLocker locker(m_authorizerLock); 164 enableAuthorizer(false); 165 166 SQLiteStatement statement(*this, "PRAGMA max_page_count = " + String::number(newMaxPageCount)); 167 statement.prepare(); 168 if (statement.step() != SQLResultRow) 169 #if OS(WINDOWS) 170 LOG_ERROR("Failed to set maximum size of database to %I64i bytes", static_cast<long long>(size)); 171 #else 172 LOG_ERROR("Failed to set maximum size of database to %lli bytes", static_cast<long long>(size)); 173 #endif 174 175 enableAuthorizer(true); 176 177 } 178 179 int SQLiteDatabase::pageSize() 180 { 181 // Since the page size of a database is locked in at creation and therefore cannot be dynamic, 182 // we can cache the value for future use 183 if (m_pageSize == -1) { 184 MutexLocker locker(m_authorizerLock); 185 enableAuthorizer(false); 186 187 SQLiteStatement statement(*this, "PRAGMA page_size"); 188 m_pageSize = statement.getColumnInt(0); 189 190 enableAuthorizer(true); 191 } 192 193 return m_pageSize; 194 } 195 196 int64_t SQLiteDatabase::freeSpaceSize() 197 { 198 int64_t freelistCount = 0; 199 200 { 201 MutexLocker locker(m_authorizerLock); 202 enableAuthorizer(false); 203 // Note: freelist_count was added in SQLite 3.4.1. 204 SQLiteStatement statement(*this, "PRAGMA freelist_count"); 205 freelistCount = statement.getColumnInt64(0); 206 enableAuthorizer(true); 207 } 208 209 return freelistCount * pageSize(); 210 } 211 212 int64_t SQLiteDatabase::totalSize() 213 { 214 int64_t pageCount = 0; 215 216 { 217 MutexLocker locker(m_authorizerLock); 218 enableAuthorizer(false); 219 SQLiteStatement statement(*this, "PRAGMA page_count"); 220 pageCount = statement.getColumnInt64(0); 221 enableAuthorizer(true); 222 } 223 224 return pageCount * pageSize(); 225 } 226 227 void SQLiteDatabase::setSynchronous(SynchronousPragma sync) 228 { 229 executeCommand(makeString("PRAGMA synchronous = ", String::number(sync))); 230 } 231 232 void SQLiteDatabase::setBusyTimeout(int ms) 233 { 234 if (m_db) 235 sqlite3_busy_timeout(m_db, ms); 236 else 237 LOG(SQLDatabase, "BusyTimeout set on non-open database"); 238 } 239 240 void SQLiteDatabase::setBusyHandler(int(*handler)(void*, int)) 241 { 242 if (m_db) 243 sqlite3_busy_handler(m_db, handler, NULL); 244 else 245 LOG(SQLDatabase, "Busy handler set on non-open database"); 246 } 247 248 bool SQLiteDatabase::executeCommand(const String& sql) 249 { 250 return SQLiteStatement(*this, sql).executeCommand(); 251 } 252 253 bool SQLiteDatabase::returnsAtLeastOneResult(const String& sql) 254 { 255 return SQLiteStatement(*this, sql).returnsAtLeastOneResult(); 256 } 257 258 bool SQLiteDatabase::tableExists(const String& tablename) 259 { 260 if (!isOpen()) 261 return false; 262 263 String statement = "SELECT name FROM sqlite_master WHERE type = 'table' AND name = '" + tablename + "';"; 264 265 SQLiteStatement sql(*this, statement); 266 sql.prepare(); 267 return sql.step() == SQLITE_ROW; 268 } 269 270 void SQLiteDatabase::clearAllTables() 271 { 272 String query = "SELECT name FROM sqlite_master WHERE type='table';"; 273 Vector<String> tables; 274 if (!SQLiteStatement(*this, query).returnTextResults(0, tables)) { 275 LOG(SQLDatabase, "Unable to retrieve list of tables from database"); 276 return; 277 } 278 279 for (Vector<String>::iterator table = tables.begin(); table != tables.end(); ++table ) { 280 if (*table == "sqlite_sequence") 281 continue; 282 if (!executeCommand("DROP TABLE " + *table)) 283 LOG(SQLDatabase, "Unable to drop table %s", (*table).ascii().data()); 284 } 285 } 286 287 void SQLiteDatabase::runVacuumCommand() 288 { 289 if (!executeCommand("VACUUM;")) 290 LOG(SQLDatabase, "Unable to vacuum database - %s", lastErrorMsg()); 291 } 292 293 void SQLiteDatabase::runIncrementalVacuumCommand() 294 { 295 MutexLocker locker(m_authorizerLock); 296 enableAuthorizer(false); 297 298 if (!executeCommand("PRAGMA incremental_vacuum")) 299 LOG(SQLDatabase, "Unable to run incremental vacuum - %s", lastErrorMsg()); 300 301 enableAuthorizer(true); 302 } 303 304 int64_t SQLiteDatabase::lastInsertRowID() 305 { 306 if (!m_db) 307 return 0; 308 return sqlite3_last_insert_rowid(m_db); 309 } 310 311 int SQLiteDatabase::lastChanges() 312 { 313 if (!m_db) 314 return 0; 315 return sqlite3_changes(m_db); 316 } 317 318 int SQLiteDatabase::lastError() 319 { 320 return m_db ? sqlite3_errcode(m_db) : SQLITE_ERROR; 321 } 322 323 const char* SQLiteDatabase::lastErrorMsg() 324 { 325 return sqlite3_errmsg(m_db); 326 } 327 328 #ifndef NDEBUG 329 void SQLiteDatabase::disableThreadingChecks() 330 { 331 // This doesn't guarantee that SQList was compiled with -DTHREADSAFE, or that you haven't turned off the mutexes. 332 #if SQLITE_VERSION_NUMBER >= 3003001 333 m_sharable = true; 334 #else 335 ASSERT(0); // Your SQLite doesn't support sharing handles across threads. 336 #endif 337 } 338 #endif 339 340 int SQLiteDatabase::authorizerFunction(void* userData, int actionCode, const char* parameter1, const char* parameter2, const char* /*databaseName*/, const char* /*trigger_or_view*/) 341 { 342 DatabaseAuthorizer* auth = static_cast<DatabaseAuthorizer*>(userData); 343 ASSERT(auth); 344 345 switch (actionCode) { 346 case SQLITE_CREATE_INDEX: 347 return auth->createIndex(parameter1, parameter2); 348 case SQLITE_CREATE_TABLE: 349 return auth->createTable(parameter1); 350 case SQLITE_CREATE_TEMP_INDEX: 351 return auth->createTempIndex(parameter1, parameter2); 352 case SQLITE_CREATE_TEMP_TABLE: 353 return auth->createTempTable(parameter1); 354 case SQLITE_CREATE_TEMP_TRIGGER: 355 return auth->createTempTrigger(parameter1, parameter2); 356 case SQLITE_CREATE_TEMP_VIEW: 357 return auth->createTempView(parameter1); 358 case SQLITE_CREATE_TRIGGER: 359 return auth->createTrigger(parameter1, parameter2); 360 case SQLITE_CREATE_VIEW: 361 return auth->createView(parameter1); 362 case SQLITE_DELETE: 363 return auth->allowDelete(parameter1); 364 case SQLITE_DROP_INDEX: 365 return auth->dropIndex(parameter1, parameter2); 366 case SQLITE_DROP_TABLE: 367 return auth->dropTable(parameter1); 368 case SQLITE_DROP_TEMP_INDEX: 369 return auth->dropTempIndex(parameter1, parameter2); 370 case SQLITE_DROP_TEMP_TABLE: 371 return auth->dropTempTable(parameter1); 372 case SQLITE_DROP_TEMP_TRIGGER: 373 return auth->dropTempTrigger(parameter1, parameter2); 374 case SQLITE_DROP_TEMP_VIEW: 375 return auth->dropTempView(parameter1); 376 case SQLITE_DROP_TRIGGER: 377 return auth->dropTrigger(parameter1, parameter2); 378 case SQLITE_DROP_VIEW: 379 return auth->dropView(parameter1); 380 case SQLITE_INSERT: 381 return auth->allowInsert(parameter1); 382 case SQLITE_PRAGMA: 383 return auth->allowPragma(parameter1, parameter2); 384 case SQLITE_READ: 385 return auth->allowRead(parameter1, parameter2); 386 case SQLITE_SELECT: 387 return auth->allowSelect(); 388 case SQLITE_TRANSACTION: 389 return auth->allowTransaction(); 390 case SQLITE_UPDATE: 391 return auth->allowUpdate(parameter1, parameter2); 392 case SQLITE_ATTACH: 393 return auth->allowAttach(parameter1); 394 case SQLITE_DETACH: 395 return auth->allowDetach(parameter1); 396 case SQLITE_ALTER_TABLE: 397 return auth->allowAlterTable(parameter1, parameter2); 398 case SQLITE_REINDEX: 399 return auth->allowReindex(parameter1); 400 #if SQLITE_VERSION_NUMBER >= 3003013 401 case SQLITE_ANALYZE: 402 return auth->allowAnalyze(parameter1); 403 case SQLITE_CREATE_VTABLE: 404 return auth->createVTable(parameter1, parameter2); 405 case SQLITE_DROP_VTABLE: 406 return auth->dropVTable(parameter1, parameter2); 407 case SQLITE_FUNCTION: 408 return auth->allowFunction(parameter2); 409 #endif 410 default: 411 ASSERT_NOT_REACHED(); 412 return SQLAuthDeny; 413 } 414 } 415 416 void SQLiteDatabase::setAuthorizer(PassRefPtr<DatabaseAuthorizer> auth) 417 { 418 if (!m_db) { 419 LOG_ERROR("Attempt to set an authorizer on a non-open SQL database"); 420 ASSERT_NOT_REACHED(); 421 return; 422 } 423 424 MutexLocker locker(m_authorizerLock); 425 426 m_authorizer = auth; 427 428 enableAuthorizer(true); 429 } 430 431 void SQLiteDatabase::enableAuthorizer(bool enable) 432 { 433 if (m_authorizer && enable) 434 sqlite3_set_authorizer(m_db, SQLiteDatabase::authorizerFunction, m_authorizer.get()); 435 else 436 sqlite3_set_authorizer(m_db, NULL, 0); 437 } 438 439 bool SQLiteDatabase::isAutoCommitOn() const 440 { 441 return sqlite3_get_autocommit(m_db); 442 } 443 444 bool SQLiteDatabase::turnOnIncrementalAutoVacuum() 445 { 446 SQLiteStatement statement(*this, "PRAGMA auto_vacuum"); 447 int autoVacuumMode = statement.getColumnInt(0); 448 int error = lastError(); 449 450 // Check if we got an error while trying to get the value of the auto_vacuum flag. 451 // If we got a SQLITE_BUSY error, then there's probably another transaction in 452 // progress on this database. In this case, keep the current value of the 453 // auto_vacuum flag and try to set it to INCREMENTAL the next time we open this 454 // database. If the error is not SQLITE_BUSY, then we probably ran into a more 455 // serious problem and should return false (to log an error message). 456 if (error != SQLITE_ROW) 457 return false; 458 459 switch (autoVacuumMode) { 460 case AutoVacuumIncremental: 461 return true; 462 case AutoVacuumFull: 463 return executeCommand("PRAGMA auto_vacuum = 2"); 464 case AutoVacuumNone: 465 default: 466 if (!executeCommand("PRAGMA auto_vacuum = 2")) 467 return false; 468 runVacuumCommand(); 469 error = lastError(); 470 return (error == SQLITE_OK); 471 } 472 } 473 474 } // namespace WebCore 475 476 #endif // ENABLE(DATABASE) 477