• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "DatabaseAuthorizer.h"
31 #include "Logging.h"
32 #include "SQLiteStatement.h"
33 
34 #include <sqlite3.h>
35 
36 namespace WebCore {
37 
38 const int SQLResultDone = SQLITE_DONE;
39 const int SQLResultError = SQLITE_ERROR;
40 const int SQLResultOk = SQLITE_OK;
41 const int SQLResultRow = SQLITE_ROW;
42 const int SQLResultSchema = SQLITE_SCHEMA;
43 const int SQLResultFull = SQLITE_FULL;
44 
45 
SQLiteDatabase()46 SQLiteDatabase::SQLiteDatabase()
47     : m_db(0)
48     , m_pageSize(-1)
49     , m_transactionInProgress(false)
50     , m_openingThread(0)
51 {
52 }
53 
~SQLiteDatabase()54 SQLiteDatabase::~SQLiteDatabase()
55 {
56     close();
57 }
58 
open(const String & filename)59 bool SQLiteDatabase::open(const String& filename)
60 {
61     close();
62 
63     // SQLite expects a null terminator on its UTF-16 strings.
64     String path = filename;
65     m_lastError = sqlite3_open16(path.charactersWithNullTermination(), &m_db);
66     if (m_lastError != SQLITE_OK) {
67         LOG_ERROR("SQLite database failed to load from %s\nCause - %s", filename.ascii().data(),
68             sqlite3_errmsg(m_db));
69         sqlite3_close(m_db);
70         m_db = 0;
71         return false;
72     }
73 
74     if (isOpen())
75         m_openingThread = currentThread();
76 
77     if (!SQLiteStatement(*this, "PRAGMA temp_store = MEMORY;").executeCommand())
78         LOG_ERROR("SQLite database could not set temp_store to memory");
79 
80     return isOpen();
81 }
82 
close()83 void SQLiteDatabase::close()
84 {
85     if (m_db) {
86         // FIXME: This is being called on themain thread during JS GC. <rdar://problem/5739818>
87         // ASSERT(currentThread() == m_openingThread);
88         sqlite3_close(m_db);
89         m_db = 0;
90     }
91 
92     m_openingThread = 0;
93 }
94 
setFullsync(bool fsync)95 void SQLiteDatabase::setFullsync(bool fsync)
96 {
97     if (fsync)
98         executeCommand("PRAGMA fullfsync = 1;");
99     else
100         executeCommand("PRAGMA fullfsync = 0;");
101 }
102 
maximumSize()103 int64_t SQLiteDatabase::maximumSize()
104 {
105     MutexLocker locker(m_authorizerLock);
106     enableAuthorizer(false);
107 
108     SQLiteStatement statement(*this, "PRAGMA max_page_count");
109     int64_t size = statement.getColumnInt64(0) * pageSize();
110 
111     enableAuthorizer(true);
112     return size;
113 }
114 
setMaximumSize(int64_t size)115 void SQLiteDatabase::setMaximumSize(int64_t size)
116 {
117     if (size < 0)
118         size = 0;
119 
120     int currentPageSize = pageSize();
121 
122     ASSERT(currentPageSize);
123     int64_t newMaxPageCount = currentPageSize ? size / currentPageSize : 0;
124 
125     MutexLocker locker(m_authorizerLock);
126     enableAuthorizer(false);
127 
128     SQLiteStatement statement(*this, "PRAGMA max_page_count = " + String::number(newMaxPageCount));
129     statement.prepare();
130     if (statement.step() != SQLResultRow)
131         LOG_ERROR("Failed to set maximum size of database to %lli bytes", size);
132 
133     enableAuthorizer(true);
134 
135 }
136 
pageSize()137 int SQLiteDatabase::pageSize()
138 {
139     // Since the page size of a database is locked in at creation and therefore cannot be dynamic,
140     // we can cache the value for future use
141     if (m_pageSize == -1) {
142         MutexLocker locker(m_authorizerLock);
143         enableAuthorizer(false);
144 
145         SQLiteStatement statement(*this, "PRAGMA page_size");
146         m_pageSize = statement.getColumnInt(0);
147 
148         enableAuthorizer(true);
149     }
150 
151     return m_pageSize;
152 }
153 
setSynchronous(SynchronousPragma sync)154 void SQLiteDatabase::setSynchronous(SynchronousPragma sync)
155 {
156     executeCommand(String::format("PRAGMA synchronous = %i", sync));
157 }
158 
setBusyTimeout(int ms)159 void SQLiteDatabase::setBusyTimeout(int ms)
160 {
161     if (m_db)
162         sqlite3_busy_timeout(m_db, ms);
163     else
164         LOG(SQLDatabase, "BusyTimeout set on non-open database");
165 }
166 
setBusyHandler(int (* handler)(void *,int))167 void SQLiteDatabase::setBusyHandler(int(*handler)(void*, int))
168 {
169     if (m_db)
170         sqlite3_busy_handler(m_db, handler, NULL);
171     else
172         LOG(SQLDatabase, "Busy handler set on non-open database");
173 }
174 
executeCommand(const String & sql)175 bool SQLiteDatabase::executeCommand(const String& sql)
176 {
177     return SQLiteStatement(*this, sql).executeCommand();
178 }
179 
returnsAtLeastOneResult(const String & sql)180 bool SQLiteDatabase::returnsAtLeastOneResult(const String& sql)
181 {
182     return SQLiteStatement(*this, sql).returnsAtLeastOneResult();
183 }
184 
tableExists(const String & tablename)185 bool SQLiteDatabase::tableExists(const String& tablename)
186 {
187     if (!isOpen())
188         return false;
189 
190     String statement = "SELECT name FROM sqlite_master WHERE type = 'table' AND name = '" + tablename + "';";
191 
192     SQLiteStatement sql(*this, statement);
193     sql.prepare();
194     return sql.step() == SQLITE_ROW;
195 }
196 
clearAllTables()197 void SQLiteDatabase::clearAllTables()
198 {
199     String query = "SELECT name FROM sqlite_master WHERE type='table';";
200     Vector<String> tables;
201     if (!SQLiteStatement(*this, query).returnTextResults(0, tables)) {
202         LOG(SQLDatabase, "Unable to retrieve list of tables from database");
203         return;
204     }
205 
206     for (Vector<String>::iterator table = tables.begin(); table != tables.end(); ++table ) {
207         if (*table == "sqlite_sequence")
208             continue;
209         if (!executeCommand("DROP TABLE " + *table))
210             LOG(SQLDatabase, "Unable to drop table %s", (*table).ascii().data());
211     }
212 }
213 
runVacuumCommand()214 void SQLiteDatabase::runVacuumCommand()
215 {
216     if (!executeCommand("VACUUM;"))
217         LOG(SQLDatabase, "Unable to vacuum database - %s", lastErrorMsg());
218 }
219 
lastInsertRowID()220 int64_t SQLiteDatabase::lastInsertRowID()
221 {
222     if (!m_db)
223         return 0;
224     return sqlite3_last_insert_rowid(m_db);
225 }
226 
lastChanges()227 int SQLiteDatabase::lastChanges()
228 {
229     if (!m_db)
230         return 0;
231     return sqlite3_changes(m_db);
232 }
233 
lastError()234 int SQLiteDatabase::lastError()
235 {
236     return m_db ? sqlite3_errcode(m_db) : SQLITE_ERROR;
237 }
238 
lastErrorMsg()239 const char* SQLiteDatabase::lastErrorMsg()
240 {
241     return sqlite3_errmsg(m_db);
242 }
243 
authorizerFunction(void * userData,int actionCode,const char * parameter1,const char * parameter2,const char *,const char *)244 int SQLiteDatabase::authorizerFunction(void* userData, int actionCode, const char* parameter1, const char* parameter2, const char* /*databaseName*/, const char* /*trigger_or_view*/)
245 {
246     DatabaseAuthorizer* auth = static_cast<DatabaseAuthorizer*>(userData);
247     ASSERT(auth);
248 
249     switch (actionCode) {
250         case SQLITE_CREATE_INDEX:
251             return auth->createIndex(parameter1, parameter2);
252         case SQLITE_CREATE_TABLE:
253             return auth->createTable(parameter1);
254         case SQLITE_CREATE_TEMP_INDEX:
255             return auth->createTempIndex(parameter1, parameter2);
256         case SQLITE_CREATE_TEMP_TABLE:
257             return auth->createTempTable(parameter1);
258         case SQLITE_CREATE_TEMP_TRIGGER:
259             return auth->createTempTrigger(parameter1, parameter2);
260         case SQLITE_CREATE_TEMP_VIEW:
261             return auth->createTempView(parameter1);
262         case SQLITE_CREATE_TRIGGER:
263             return auth->createTrigger(parameter1, parameter2);
264         case SQLITE_CREATE_VIEW:
265             return auth->createView(parameter1);
266         case SQLITE_DELETE:
267             return auth->allowDelete(parameter1);
268         case SQLITE_DROP_INDEX:
269             return auth->dropIndex(parameter1, parameter2);
270         case SQLITE_DROP_TABLE:
271             return auth->dropTable(parameter1);
272         case SQLITE_DROP_TEMP_INDEX:
273             return auth->dropTempIndex(parameter1, parameter2);
274         case SQLITE_DROP_TEMP_TABLE:
275             return auth->dropTempTable(parameter1);
276         case SQLITE_DROP_TEMP_TRIGGER:
277             return auth->dropTempTrigger(parameter1, parameter2);
278         case SQLITE_DROP_TEMP_VIEW:
279             return auth->dropTempView(parameter1);
280         case SQLITE_DROP_TRIGGER:
281             return auth->dropTrigger(parameter1, parameter2);
282         case SQLITE_DROP_VIEW:
283             return auth->dropView(parameter1);
284         case SQLITE_INSERT:
285             return auth->allowInsert(parameter1);
286         case SQLITE_PRAGMA:
287             return auth->allowPragma(parameter1, parameter2);
288         case SQLITE_READ:
289             return auth->allowRead(parameter1, parameter2);
290         case SQLITE_SELECT:
291             return auth->allowSelect();
292         case SQLITE_TRANSACTION:
293             return auth->allowTransaction();
294         case SQLITE_UPDATE:
295             return auth->allowUpdate(parameter1, parameter2);
296         case SQLITE_ATTACH:
297             return auth->allowAttach(parameter1);
298         case SQLITE_DETACH:
299             return auth->allowDetach(parameter1);
300         case SQLITE_ALTER_TABLE:
301             return auth->allowAlterTable(parameter1, parameter2);
302         case SQLITE_REINDEX:
303             return auth->allowReindex(parameter1);
304 #if SQLITE_VERSION_NUMBER >= 3003013
305         case SQLITE_ANALYZE:
306             return auth->allowAnalyze(parameter1);
307         case SQLITE_CREATE_VTABLE:
308             return auth->createVTable(parameter1, parameter2);
309         case SQLITE_DROP_VTABLE:
310             return auth->dropVTable(parameter1, parameter2);
311         case SQLITE_FUNCTION:
312             return auth->allowFunction(parameter1);
313 #endif
314         default:
315             ASSERT_NOT_REACHED();
316             return SQLAuthDeny;
317     }
318 }
319 
setAuthorizer(PassRefPtr<DatabaseAuthorizer> auth)320 void SQLiteDatabase::setAuthorizer(PassRefPtr<DatabaseAuthorizer> auth)
321 {
322     if (!m_db) {
323         LOG_ERROR("Attempt to set an authorizer on a non-open SQL database");
324         ASSERT_NOT_REACHED();
325         return;
326     }
327 
328     MutexLocker locker(m_authorizerLock);
329 
330     m_authorizer = auth;
331 
332     enableAuthorizer(true);
333 }
334 
enableAuthorizer(bool enable)335 void SQLiteDatabase::enableAuthorizer(bool enable)
336 {
337     if (m_authorizer && enable)
338         sqlite3_set_authorizer(m_db, SQLiteDatabase::authorizerFunction, m_authorizer.get());
339     else
340         sqlite3_set_authorizer(m_db, NULL, 0);
341 }
342 
lock()343 void SQLiteDatabase::lock()
344 {
345     m_lockingMutex.lock();
346 }
347 
unlock()348 void SQLiteDatabase::unlock()
349 {
350     m_lockingMutex.unlock();
351 }
352 
353 } // namespace WebCore
354