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