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