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