2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
14 * THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
28 #include "SQLiteDatabase.h"
30 #include "DatabaseAuthorizer.h"
32 #include "SQLiteFileSystem.h"
33 #include "SQLiteStatement.h"
35 #include <wtf/Threading.h>
36 #include <wtf/text/CString.h>
37 #include <wtf/text/WTFString.h>
41 static const char notOpenErrorMessage[] = "database is not open";
43 static void unauthorizedSQLFunction(sqlite3_context *context, int, sqlite3_value **)
45 const char* functionName = (const char*)sqlite3_user_data(context);
46 String errorMessage = String::format("Function %s is unauthorized", functionName);
47 sqlite3_result_error(context, errorMessage.utf8().data(), -1);
50 SQLiteDatabase::SQLiteDatabase()
53 , m_transactionInProgress(false)
56 , m_openError(SQLITE_ERROR)
57 , m_openErrorMessage()
58 , m_lastChangesCount(0)
62 SQLiteDatabase::~SQLiteDatabase()
67 bool SQLiteDatabase::open(const String& filename, bool forWebSQLDatabase)
71 m_openError = SQLiteFileSystem::openDatabase(filename, &m_db, forWebSQLDatabase);
72 if (m_openError != SQLITE_OK) {
73 m_openErrorMessage = m_db ? sqlite3_errmsg(m_db) : "sqlite_open returned null";
74 LOG_ERROR("SQLite database failed to load from %s\nCause - %s", filename.ascii().data(),
75 m_openErrorMessage.data());
81 overrideUnauthorizedFunctions();
83 m_openError = sqlite3_extended_result_codes(m_db, 1);
84 if (m_openError != SQLITE_OK) {
85 m_openErrorMessage = sqlite3_errmsg(m_db);
86 LOG_ERROR("SQLite database error when enabling extended errors - %s", m_openErrorMessage.data());
93 m_openingThread = currentThread();
95 m_openErrorMessage = "sqlite_open returned null";
97 if (!SQLiteStatement(*this, ASCIILiteral("PRAGMA temp_store = MEMORY;")).executeCommand())
98 LOG_ERROR("SQLite database could not set temp_store to memory");
100 SQLiteStatement walStatement(*this, ASCIILiteral("PRAGMA journal_mode=WAL;"));
101 int result = walStatement.step();
102 if (result != SQLITE_OK && result != SQLITE_ROW)
103 LOG_ERROR("SQLite database failed to set journal_mode to WAL, error: %s", lastErrorMsg());
106 if (result == SQLITE_ROW) {
107 String mode = walStatement.getColumnText(0);
108 if (!equalIgnoringCase(mode, "wal"))
109 LOG_ERROR("journal_mode of database should be 'wal', but is '%s'", mode.utf8().data());
116 void SQLiteDatabase::close()
119 // FIXME: This is being called on the main thread during JS GC. <rdar://problem/5739818>
120 // ASSERT(currentThread() == m_openingThread);
123 MutexLocker locker(m_databaseClosingMutex);
130 m_openError = SQLITE_ERROR;
131 m_openErrorMessage = CString();
134 void SQLiteDatabase::overrideUnauthorizedFunctions()
136 static const std::pair<const char*, int> functionParameters[] = {
142 { "fts3_tokenizer", 1 },
143 { "fts3_tokenizer", 2 },
146 for (auto& functionParameter : functionParameters)
147 sqlite3_create_function(m_db, functionParameter.first, functionParameter.second, SQLITE_UTF8, const_cast<char*>(functionParameter.first), unauthorizedSQLFunction, 0, 0);
150 void SQLiteDatabase::setFullsync(bool fsync)
153 executeCommand(ASCIILiteral("PRAGMA fullfsync = 1;"));
155 executeCommand(ASCIILiteral("PRAGMA fullfsync = 0;"));
158 int64_t SQLiteDatabase::maximumSize()
160 int64_t maxPageCount = 0;
163 MutexLocker locker(m_authorizerLock);
164 enableAuthorizer(false);
165 SQLiteStatement statement(*this, ASCIILiteral("PRAGMA max_page_count"));
166 maxPageCount = statement.getColumnInt64(0);
167 enableAuthorizer(true);
170 return maxPageCount * pageSize();
173 void SQLiteDatabase::setMaximumSize(int64_t size)
178 int currentPageSize = pageSize();
180 ASSERT(currentPageSize || !m_db);
181 int64_t newMaxPageCount = currentPageSize ? size / currentPageSize : 0;
183 MutexLocker locker(m_authorizerLock);
184 enableAuthorizer(false);
186 SQLiteStatement statement(*this, "PRAGMA max_page_count = " + String::number(newMaxPageCount));
188 if (statement.step() != SQLITE_ROW)
189 LOG_ERROR("Failed to set maximum size of database to %lli bytes", static_cast<long long>(size));
191 enableAuthorizer(true);
195 int SQLiteDatabase::pageSize()
197 // Since the page size of a database is locked in at creation and therefore cannot be dynamic,
198 // we can cache the value for future use
199 if (m_pageSize == -1) {
200 MutexLocker locker(m_authorizerLock);
201 enableAuthorizer(false);
203 SQLiteStatement statement(*this, ASCIILiteral("PRAGMA page_size"));
204 m_pageSize = statement.getColumnInt(0);
206 enableAuthorizer(true);
212 int64_t SQLiteDatabase::freeSpaceSize()
214 int64_t freelistCount = 0;
217 MutexLocker locker(m_authorizerLock);
218 enableAuthorizer(false);
219 // Note: freelist_count was added in SQLite 3.4.1.
220 SQLiteStatement statement(*this, ASCIILiteral("PRAGMA freelist_count"));
221 freelistCount = statement.getColumnInt64(0);
222 enableAuthorizer(true);
225 return freelistCount * pageSize();
228 int64_t SQLiteDatabase::totalSize()
230 int64_t pageCount = 0;
233 MutexLocker locker(m_authorizerLock);
234 enableAuthorizer(false);
235 SQLiteStatement statement(*this, ASCIILiteral("PRAGMA page_count"));
236 pageCount = statement.getColumnInt64(0);
237 enableAuthorizer(true);
240 return pageCount * pageSize();
243 void SQLiteDatabase::setSynchronous(SynchronousPragma sync)
245 executeCommand("PRAGMA synchronous = " + String::number(sync));
248 void SQLiteDatabase::setBusyTimeout(int ms)
251 sqlite3_busy_timeout(m_db, ms);
253 LOG(SQLDatabase, "BusyTimeout set on non-open database");
256 void SQLiteDatabase::setBusyHandler(int(*handler)(void*, int))
259 sqlite3_busy_handler(m_db, handler, NULL);
261 LOG(SQLDatabase, "Busy handler set on non-open database");
264 bool SQLiteDatabase::executeCommand(const String& sql)
266 return SQLiteStatement(*this, sql).executeCommand();
269 bool SQLiteDatabase::returnsAtLeastOneResult(const String& sql)
271 return SQLiteStatement(*this, sql).returnsAtLeastOneResult();
274 bool SQLiteDatabase::tableExists(const String& tablename)
279 String statement = "SELECT name FROM sqlite_master WHERE type = 'table' AND name = '" + tablename + "';";
281 SQLiteStatement sql(*this, statement);
283 return sql.step() == SQLITE_ROW;
286 void SQLiteDatabase::clearAllTables()
288 String query = ASCIILiteral("SELECT name FROM sqlite_master WHERE type='table';");
289 Vector<String> tables;
290 if (!SQLiteStatement(*this, query).returnTextResults(0, tables)) {
291 LOG(SQLDatabase, "Unable to retrieve list of tables from database");
295 for (Vector<String>::iterator table = tables.begin(); table != tables.end(); ++table ) {
296 if (*table == "sqlite_sequence")
298 if (!executeCommand("DROP TABLE " + *table))
299 LOG(SQLDatabase, "Unable to drop table %s", (*table).ascii().data());
303 int SQLiteDatabase::runVacuumCommand()
305 if (!executeCommand(ASCIILiteral("VACUUM;")))
306 LOG(SQLDatabase, "Unable to vacuum database - %s", lastErrorMsg());
310 int SQLiteDatabase::runIncrementalVacuumCommand()
312 MutexLocker locker(m_authorizerLock);
313 enableAuthorizer(false);
315 if (!executeCommand(ASCIILiteral("PRAGMA incremental_vacuum")))
316 LOG(SQLDatabase, "Unable to run incremental vacuum - %s", lastErrorMsg());
318 enableAuthorizer(true);
322 int64_t SQLiteDatabase::lastInsertRowID()
326 return sqlite3_last_insert_rowid(m_db);
329 void SQLiteDatabase::updateLastChangesCount()
334 m_lastChangesCount = sqlite3_total_changes(m_db);
337 int SQLiteDatabase::lastChanges()
342 return sqlite3_total_changes(m_db) - m_lastChangesCount;
345 int SQLiteDatabase::lastError()
347 return m_db ? sqlite3_errcode(m_db) : m_openError;
350 const char* SQLiteDatabase::lastErrorMsg()
353 return sqlite3_errmsg(m_db);
354 return m_openErrorMessage.isNull() ? notOpenErrorMessage : m_openErrorMessage.data();
358 void SQLiteDatabase::disableThreadingChecks()
360 // This doesn't guarantee that SQList was compiled with -DTHREADSAFE, or that you haven't turned off the mutexes.
361 #if SQLITE_VERSION_NUMBER >= 3003001
364 ASSERT(0); // Your SQLite doesn't support sharing handles across threads.
369 int SQLiteDatabase::authorizerFunction(void* userData, int actionCode, const char* parameter1, const char* parameter2, const char* /*databaseName*/, const char* /*trigger_or_view*/)
371 DatabaseAuthorizer* auth = static_cast<DatabaseAuthorizer*>(userData);
374 switch (actionCode) {
375 case SQLITE_CREATE_INDEX:
376 return auth->createIndex(parameter1, parameter2);
377 case SQLITE_CREATE_TABLE:
378 return auth->createTable(parameter1);
379 case SQLITE_CREATE_TEMP_INDEX:
380 return auth->createTempIndex(parameter1, parameter2);
381 case SQLITE_CREATE_TEMP_TABLE:
382 return auth->createTempTable(parameter1);
383 case SQLITE_CREATE_TEMP_TRIGGER:
384 return auth->createTempTrigger(parameter1, parameter2);
385 case SQLITE_CREATE_TEMP_VIEW:
386 return auth->createTempView(parameter1);
387 case SQLITE_CREATE_TRIGGER:
388 return auth->createTrigger(parameter1, parameter2);
389 case SQLITE_CREATE_VIEW:
390 return auth->createView(parameter1);
392 return auth->allowDelete(parameter1);
393 case SQLITE_DROP_INDEX:
394 return auth->dropIndex(parameter1, parameter2);
395 case SQLITE_DROP_TABLE:
396 return auth->dropTable(parameter1);
397 case SQLITE_DROP_TEMP_INDEX:
398 return auth->dropTempIndex(parameter1, parameter2);
399 case SQLITE_DROP_TEMP_TABLE:
400 return auth->dropTempTable(parameter1);
401 case SQLITE_DROP_TEMP_TRIGGER:
402 return auth->dropTempTrigger(parameter1, parameter2);
403 case SQLITE_DROP_TEMP_VIEW:
404 return auth->dropTempView(parameter1);
405 case SQLITE_DROP_TRIGGER:
406 return auth->dropTrigger(parameter1, parameter2);
407 case SQLITE_DROP_VIEW:
408 return auth->dropView(parameter1);
410 return auth->allowInsert(parameter1);
412 return auth->allowPragma(parameter1, parameter2);
414 return auth->allowRead(parameter1, parameter2);
416 return auth->allowSelect();
417 case SQLITE_TRANSACTION:
418 return auth->allowTransaction();
420 return auth->allowUpdate(parameter1, parameter2);
422 return auth->allowAttach(parameter1);
424 return auth->allowDetach(parameter1);
425 case SQLITE_ALTER_TABLE:
426 return auth->allowAlterTable(parameter1, parameter2);
428 return auth->allowReindex(parameter1);
429 #if SQLITE_VERSION_NUMBER >= 3003013
431 return auth->allowAnalyze(parameter1);
432 case SQLITE_CREATE_VTABLE:
433 return auth->createVTable(parameter1, parameter2);
434 case SQLITE_DROP_VTABLE:
435 return auth->dropVTable(parameter1, parameter2);
436 case SQLITE_FUNCTION:
437 return auth->allowFunction(parameter2);
440 ASSERT_NOT_REACHED();
445 void SQLiteDatabase::setAuthorizer(PassRefPtr<DatabaseAuthorizer> auth)
448 LOG_ERROR("Attempt to set an authorizer on a non-open SQL database");
449 ASSERT_NOT_REACHED();
453 MutexLocker locker(m_authorizerLock);
457 enableAuthorizer(true);
460 void SQLiteDatabase::enableAuthorizer(bool enable)
462 if (m_authorizer && enable)
463 sqlite3_set_authorizer(m_db, SQLiteDatabase::authorizerFunction, m_authorizer.get());
465 sqlite3_set_authorizer(m_db, NULL, 0);
468 bool SQLiteDatabase::isAutoCommitOn() const
470 return sqlite3_get_autocommit(m_db);
473 bool SQLiteDatabase::turnOnIncrementalAutoVacuum()
475 SQLiteStatement statement(*this, ASCIILiteral("PRAGMA auto_vacuum"));
476 int autoVacuumMode = statement.getColumnInt(0);
477 int error = lastError();
479 // Check if we got an error while trying to get the value of the auto_vacuum flag.
480 // If we got a SQLITE_BUSY error, then there's probably another transaction in
481 // progress on this database. In this case, keep the current value of the
482 // auto_vacuum flag and try to set it to INCREMENTAL the next time we open this
483 // database. If the error is not SQLITE_BUSY, then we probably ran into a more
484 // serious problem and should return false (to log an error message).
485 if (error != SQLITE_ROW)
488 switch (autoVacuumMode) {
489 case AutoVacuumIncremental:
492 return executeCommand(ASCIILiteral("PRAGMA auto_vacuum = 2"));
495 if (!executeCommand(ASCIILiteral("PRAGMA auto_vacuum = 2")))
499 return (error == SQLITE_OK);
503 static void destroyCollationFunction(void* arg)
505 auto f = static_cast<std::function<int(int, const void*, int, const void*)>*>(arg);
509 static int callCollationFunction(void* arg, int aLength, const void* a, int bLength, const void* b)
511 auto f = static_cast<std::function<int(int, const void*, int, const void*)>*>(arg);
512 return (*f)(aLength, a, bLength, b);
515 void SQLiteDatabase::setCollationFunction(const String& collationName, std::function<int(int, const void*, int, const void*)> collationFunction)
517 auto functionObject = new std::function<int(int, const void*, int, const void*)>(collationFunction);
518 sqlite3_create_collation_v2(m_db, collationName.utf8().data(), SQLITE_UTF8, functionObject, callCollationFunction, destroyCollationFunction);
521 void SQLiteDatabase::removeCollationFunction(const String& collationName)
523 sqlite3_create_collation_v2(m_db, collationName.utf8().data(), SQLITE_UTF8, nullptr, nullptr, nullptr);
526 } // namespace WebCore