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