OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2010 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 17 matching lines...) Expand all Loading... |
28 | 28 |
29 #include "config.h" | 29 #include "config.h" |
30 #include "IDBFactoryBackendImpl.h" | 30 #include "IDBFactoryBackendImpl.h" |
31 | 31 |
32 #include "DOMStringList.h" | 32 #include "DOMStringList.h" |
33 #include "FileSystem.h" | 33 #include "FileSystem.h" |
34 #include "IDBDatabaseBackendImpl.h" | 34 #include "IDBDatabaseBackendImpl.h" |
35 #include "IDBDatabaseException.h" | 35 #include "IDBDatabaseException.h" |
36 #include "IDBSQLiteDatabase.h" | 36 #include "IDBSQLiteDatabase.h" |
37 #include "IDBTransactionCoordinator.h" | 37 #include "IDBTransactionCoordinator.h" |
| 38 #include "SQLiteStatement.h" |
| 39 #include "SQLiteTransaction.h" |
38 #include "SecurityOrigin.h" | 40 #include "SecurityOrigin.h" |
39 #include <wtf/Threading.h> | 41 #include <wtf/Threading.h> |
40 #include <wtf/UnusedParam.h> | 42 #include <wtf/UnusedParam.h> |
41 | 43 |
42 #if ENABLE(INDEXED_DATABASE) | 44 #if ENABLE(INDEXED_DATABASE) |
43 | 45 |
44 namespace WebCore { | 46 namespace WebCore { |
45 | 47 |
46 IDBFactoryBackendImpl::IDBFactoryBackendImpl() | 48 IDBFactoryBackendImpl::IDBFactoryBackendImpl() |
47 : m_transactionCoordinator(IDBTransactionCoordinator::create()) | 49 : m_transactionCoordinator(IDBTransactionCoordinator::create()) |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 | 88 |
87 // FIXME: Error checking? | 89 // FIXME: Error checking? |
88 sqliteDatabase->db().setMaximumSize(maximumSize); | 90 sqliteDatabase->db().setMaximumSize(maximumSize); |
89 sqliteDatabase->db().turnOnIncrementalAutoVacuum(); | 91 sqliteDatabase->db().turnOnIncrementalAutoVacuum(); |
90 | 92 |
91 return sqliteDatabase.release(); | 93 return sqliteDatabase.release(); |
92 } | 94 } |
93 | 95 |
94 static bool createTables(SQLiteDatabase& sqliteDatabase) | 96 static bool createTables(SQLiteDatabase& sqliteDatabase) |
95 { | 97 { |
| 98 if (sqliteDatabase.tableExists("Databases")) |
| 99 return true; |
| 100 |
96 static const char* commands[] = { | 101 static const char* commands[] = { |
97 "CREATE TABLE IF NOT EXISTS Databases (id INTEGER PRIMARY KEY, name TEXT
NOT NULL, description TEXT NOT NULL, version TEXT NOT NULL)", | 102 "CREATE TABLE Databases (id INTEGER PRIMARY KEY, name TEXT NOT NULL, des
cription TEXT NOT NULL, version TEXT NOT NULL)", |
98 "CREATE UNIQUE INDEX IF NOT EXISTS Databases_name ON Databases(name)", | 103 "CREATE UNIQUE INDEX Databases_name ON Databases(name)", |
99 | 104 |
100 "CREATE TABLE IF NOT EXISTS ObjectStores (id INTEGER PRIMARY KEY, name T
EXT NOT NULL, keyPath TEXT, doAutoIncrement INTEGER NOT NULL, databaseId INTEGER
NOT NULL REFERENCES Databases(id))", | 105 "CREATE TABLE ObjectStores (id INTEGER PRIMARY KEY, name TEXT NOT NULL,
keyPath TEXT, doAutoIncrement INTEGER NOT NULL, databaseId INTEGER NOT NULL REFE
RENCES Databases(id))", |
101 "CREATE UNIQUE INDEX IF NOT EXISTS ObjectStores_composit ON ObjectStores
(databaseId, name)", | 106 "CREATE UNIQUE INDEX ObjectStores_composit ON ObjectStores(databaseId, n
ame)", |
102 | 107 |
103 "CREATE TABLE IF NOT EXISTS Indexes (id INTEGER PRIMARY KEY, objectStore
Id INTEGER NOT NULL REFERENCES ObjectStore(id), name TEXT NOT NULL, keyPath TEXT
, isUnique INTEGER NOT NULL)", | 108 "CREATE TABLE Indexes (id INTEGER PRIMARY KEY, objectStoreId INTEGER NOT
NULL REFERENCES ObjectStore(id), name TEXT NOT NULL, keyPath TEXT, isUnique INT
EGER NOT NULL)", |
104 "CREATE UNIQUE INDEX IF NOT EXISTS Indexes_composit ON Indexes(objectSto
reId, name)", | 109 "CREATE UNIQUE INDEX Indexes_composit ON Indexes(objectStoreId, name)", |
105 | 110 |
106 "CREATE TABLE IF NOT EXISTS ObjectStoreData (id INTEGER PRIMARY KEY, obj
ectStoreId INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate
INTEGER, keyNumber INTEGER, value TEXT NOT NULL)", | 111 "CREATE TABLE ObjectStoreData (id INTEGER PRIMARY KEY, objectStoreId INT
EGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate INTEGER, keyNu
mber INTEGER, value TEXT NOT NULL)", |
107 "CREATE UNIQUE INDEX IF NOT EXISTS ObjectStoreData_composit ON ObjectSto
reData(keyString, keyDate, keyNumber, objectStoreId)", | 112 "CREATE UNIQUE INDEX ObjectStoreData_composit ON ObjectStoreData(keyStri
ng, keyDate, keyNumber, objectStoreId)", |
108 | 113 |
109 "CREATE TABLE IF NOT EXISTS IndexData (id INTEGER PRIMARY KEY, indexId I
NTEGER NOT NULL REFERENCES Indexes(id), keyString TEXT, keyDate INTEGER, keyNumb
er INTEGER, objectStoreDataId INTEGER NOT NULL REFERENCES ObjectStoreData(id))", | 114 "CREATE TABLE IndexData (id INTEGER PRIMARY KEY, indexId INTEGER NOT NUL
L REFERENCES Indexes(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, ob
jectStoreDataId INTEGER NOT NULL REFERENCES ObjectStoreData(id))", |
110 "CREATE INDEX IF NOT EXISTS IndexData_composit ON IndexData(keyString, k
eyDate, keyNumber, indexId)", | 115 "CREATE INDEX IndexData_composit ON IndexData(keyString, keyDate, keyNum
ber, indexId)", |
111 "CREATE INDEX IF NOT EXISTS IndexData_objectStoreDataId ON IndexData(obj
ectStoreDataId)", | 116 "CREATE INDEX IndexData_objectStoreDataId ON IndexData(objectStoreDataId
)", |
112 "CREATE INDEX IF NOT EXISTS IndexData_indexId ON IndexData(indexId)" | 117 "CREATE INDEX IndexData_indexId ON IndexData(indexId)", |
113 }; | 118 }; |
114 | 119 |
| 120 SQLiteTransaction transaction(sqliteDatabase, false); |
| 121 transaction.begin(); |
115 for (size_t i = 0; i < arraysize(commands); ++i) { | 122 for (size_t i = 0; i < arraysize(commands); ++i) { |
116 if (!sqliteDatabase.executeCommand(commands[i])) { | 123 if (!sqliteDatabase.executeCommand(commands[i])) { |
117 // FIXME: We should try to recover from this situation. Maybe nuke t
he database and start over? | 124 // FIXME: We should try to recover from this situation. Maybe nuke t
he database and start over? |
118 LOG_ERROR("Failed to run the following command for IndexedDB: %s", c
ommands[i]); | 125 LOG_ERROR("Failed to run the following command for IndexedDB: %s", c
ommands[i]); |
119 return false; | 126 return false; |
120 } | 127 } |
121 } | 128 } |
| 129 transaction.commit(); |
| 130 return true; |
| 131 } |
| 132 |
| 133 static bool createMetaDataTable(SQLiteDatabase& sqliteDatabase) |
| 134 { |
| 135 static const char* commands[] = { |
| 136 "CREATE TABLE MetaData (name TEXT PRIMARY KEY, value NONE)", |
| 137 "INSERT INTO MetaData VALUES ('version', 1)", |
| 138 }; |
| 139 |
| 140 SQLiteTransaction transaction(sqliteDatabase, false); |
| 141 transaction.begin(); |
| 142 for (size_t i = 0; i < arraysize(commands); ++i) { |
| 143 if (!sqliteDatabase.executeCommand(commands[i])) |
| 144 return false; |
| 145 } |
| 146 transaction.commit(); |
| 147 return true; |
| 148 } |
| 149 |
| 150 static bool getDatabaseVersion(SQLiteDatabase& sqliteDatabase, int* databaseVers
ion) |
| 151 { |
| 152 SQLiteStatement query(sqliteDatabase, "SELECT value FROM MetaData WHERE name
= 'version'"); |
| 153 if (query.prepare() != SQLResultOk || query.step() != SQLResultRow) |
| 154 return false; |
| 155 |
| 156 *databaseVersion = query.getColumnInt(0); |
| 157 return query.finalize() == SQLResultOk; |
| 158 } |
| 159 |
| 160 static bool migrateDatabase(SQLiteDatabase& sqliteDatabase) |
| 161 { |
| 162 if (!sqliteDatabase.tableExists("MetaData")) { |
| 163 if (!createMetaDataTable(sqliteDatabase)) |
| 164 return false; |
| 165 } |
| 166 |
| 167 int databaseVersion; |
| 168 if (!getDatabaseVersion(sqliteDatabase, &databaseVersion)) |
| 169 return false; |
| 170 |
| 171 if (databaseVersion == 1) { |
| 172 static const char* commands[] = { |
| 173 "DROP TABLE IF EXISTS ObjectStoreData2", |
| 174 "CREATE TABLE ObjectStoreData2 (id INTEGER PRIMARY KEY, objectStoreI
d INTEGER NOT NULL REFERENCES ObjectStore(id), keyString TEXT, keyDate REAL, key
Number REAL, value TEXT NOT NULL)", |
| 175 "INSERT INTO ObjectStoreData2 SELECT * FROM ObjectStoreData", |
| 176 "DROP TABLE ObjectStoreData", // This depends on SQLite not enforcin
g referential consistency. |
| 177 "ALTER TABLE ObjectStoreData2 RENAME TO ObjectStoreData", |
| 178 "CREATE UNIQUE INDEX ObjectStoreData_composit ON ObjectStoreData(key
String, keyDate, keyNumber, objectStoreId)", |
| 179 "DROP TABLE IF EXISTS IndexData2", // This depends on SQLite not enf
orcing referential consistency. |
| 180 "CREATE TABLE IndexData2 (id INTEGER PRIMARY KEY, indexId INTEGER NO
T NULL REFERENCES Indexes(id), keyString TEXT, keyDate REAL, keyNumber REAL, obj
ectStoreDataId INTEGER NOT NULL REFERENCES ObjectStoreData(id))", |
| 181 "INSERT INTO IndexData2 SELECT * FROM IndexData", |
| 182 "DROP TABLE IndexData", |
| 183 "ALTER TABLE IndexData2 RENAME TO IndexData", |
| 184 "CREATE INDEX IndexData_composit ON IndexData(keyString, keyDate, ke
yNumber, indexId)", |
| 185 "CREATE INDEX IndexData_objectStoreDataId ON IndexData(objectStoreDa
taId)", |
| 186 "CREATE INDEX IndexData_indexId ON IndexData(indexId)", |
| 187 "UPDATE MetaData SET value = 2 WHERE name = 'version'", |
| 188 }; |
| 189 |
| 190 SQLiteTransaction transaction(sqliteDatabase, false); |
| 191 transaction.begin(); |
| 192 for (size_t i = 0; i < arraysize(commands); ++i) { |
| 193 if (!sqliteDatabase.executeCommand(commands[i])) { |
| 194 LOG_ERROR("Failed to run the following command for IndexedDB: %s
", commands[i]); |
| 195 return false; |
| 196 } |
| 197 } |
| 198 transaction.commit(); |
| 199 |
| 200 databaseVersion = 2; |
| 201 } |
| 202 |
122 return true; | 203 return true; |
123 } | 204 } |
124 | 205 |
125 void IDBFactoryBackendImpl::open(const String& name, PassRefPtr<IDBCallbacks> ca
llbacks, PassRefPtr<SecurityOrigin> securityOrigin, Frame*, const String& dataDi
r, int64_t maximumSize) | 206 void IDBFactoryBackendImpl::open(const String& name, PassRefPtr<IDBCallbacks> ca
llbacks, PassRefPtr<SecurityOrigin> securityOrigin, Frame*, const String& dataDi
r, int64_t maximumSize) |
126 { | 207 { |
127 String fileIdentifier = securityOrigin->databaseIdentifier(); | 208 String fileIdentifier = securityOrigin->databaseIdentifier(); |
128 String uniqueIdentifier = fileIdentifier + "@" + name; | 209 String uniqueIdentifier = fileIdentifier + "@" + name; |
129 IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(uniqueIdentif
ier); | 210 IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(uniqueIdentif
ier); |
130 if (it != m_databaseBackendMap.end()) { | 211 if (it != m_databaseBackendMap.end()) { |
131 callbacks->onSuccess(it->second); | 212 callbacks->onSuccess(it->second); |
132 return; | 213 return; |
133 } | 214 } |
134 | 215 |
135 // FIXME: Everything from now on should be done on another thread. | 216 // FIXME: Everything from now on should be done on another thread. |
136 | 217 |
137 RefPtr<IDBSQLiteDatabase> sqliteDatabase; | 218 RefPtr<IDBSQLiteDatabase> sqliteDatabase; |
138 SQLiteDatabaseMap::iterator it2 = m_sqliteDatabaseMap.find(fileIdentifier); | 219 SQLiteDatabaseMap::iterator it2 = m_sqliteDatabaseMap.find(fileIdentifier); |
139 if (it2 != m_sqliteDatabaseMap.end()) | 220 if (it2 != m_sqliteDatabaseMap.end()) |
140 sqliteDatabase = it2->second; | 221 sqliteDatabase = it2->second; |
141 else { | 222 else { |
142 sqliteDatabase = openSQLiteDatabase(securityOrigin.get(), dataDir, maxim
umSize, fileIdentifier, this); | 223 sqliteDatabase = openSQLiteDatabase(securityOrigin.get(), dataDir, maxim
umSize, fileIdentifier, this); |
143 | 224 |
144 if (!sqliteDatabase || !createTables(sqliteDatabase->db())) { | 225 if (!sqliteDatabase || !createTables(sqliteDatabase->db()) || !migrateDa
tabase(sqliteDatabase->db())) { |
145 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UN
KNOWN_ERR, "Internal error.")); | 226 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UN
KNOWN_ERR, "Internal error.")); |
| 227 m_sqliteDatabaseMap.set(fileIdentifier, 0); |
146 return; | 228 return; |
147 } | 229 } |
148 m_sqliteDatabaseMap.set(fileIdentifier, sqliteDatabase.get()); | 230 m_sqliteDatabaseMap.set(fileIdentifier, sqliteDatabase.get()); |
149 } | 231 } |
150 | 232 |
151 RefPtr<IDBDatabaseBackendImpl> databaseBackend = IDBDatabaseBackendImpl::cre
ate(name, sqliteDatabase.get(), m_transactionCoordinator.get(), this, uniqueIden
tifier); | 233 RefPtr<IDBDatabaseBackendImpl> databaseBackend = IDBDatabaseBackendImpl::cre
ate(name, sqliteDatabase.get(), m_transactionCoordinator.get(), this, uniqueIden
tifier); |
152 callbacks->onSuccess(databaseBackend.get()); | 234 callbacks->onSuccess(databaseBackend.get()); |
153 m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get()); | 235 m_databaseBackendMap.set(uniqueIdentifier, databaseBackend.get()); |
154 } | 236 } |
155 | 237 |
156 } // namespace WebCore | 238 } // namespace WebCore |
157 | 239 |
158 #endif // ENABLE(INDEXED_DATABASE) | 240 #endif // ENABLE(INDEXED_DATABASE) |
159 | |
OLD | NEW |