Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / modules / webdatabase / Database.cpp
1 /*
2  * Copyright (C) 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "modules/webdatabase/Database.h"
28
29 #include "core/dom/CrossThreadTask.h"
30 #include "core/dom/ExceptionCode.h"
31 #include "core/html/VoidCallback.h"
32 #include "modules/webdatabase/ChangeVersionData.h"
33 #include "modules/webdatabase/ChangeVersionWrapper.h"
34 #include "modules/webdatabase/DatabaseAuthorizer.h"
35 #include "modules/webdatabase/DatabaseContext.h"
36 #include "modules/webdatabase/DatabaseManager.h"
37 #include "modules/webdatabase/DatabaseTask.h"
38 #include "modules/webdatabase/DatabaseThread.h"
39 #include "modules/webdatabase/DatabaseTracker.h"
40 #include "modules/webdatabase/SQLError.h"
41 #include "modules/webdatabase/SQLTransaction.h"
42 #include "modules/webdatabase/SQLTransactionBackend.h"
43 #include "modules/webdatabase/SQLTransactionCallback.h"
44 #include "modules/webdatabase/SQLTransactionClient.h"
45 #include "modules/webdatabase/SQLTransactionCoordinator.h"
46 #include "modules/webdatabase/SQLTransactionErrorCallback.h"
47 #include "modules/webdatabase/sqlite/SQLiteStatement.h"
48 #include "modules/webdatabase/sqlite/SQLiteTransaction.h"
49 #include "platform/Logging.h"
50 #include "platform/weborigin/DatabaseIdentifier.h"
51 #include "public/platform/Platform.h"
52 #include "public/platform/WebDatabaseObserver.h"
53
54 // Registering "opened" databases with the DatabaseTracker
55 // =======================================================
56 // The DatabaseTracker maintains a list of databases that have been
57 // "opened" so that the client can call interrupt or delete on every database
58 // associated with a DatabaseContext.
59 //
60 // We will only call DatabaseTracker::addOpenDatabase() to add the database
61 // to the tracker as opened when we've succeeded in opening the database,
62 // and will set m_opened to true. Similarly, we only call
63 // DatabaseTracker::removeOpenDatabase() to remove the database from the
64 // tracker when we set m_opened to false in closeDatabase(). This sets up
65 // a simple symmetry between open and close operations, and a direct
66 // correlation to adding and removing databases from the tracker's list,
67 // thus ensuring that we have a correct list for the interrupt and
68 // delete operations to work on.
69 //
70 // The only databases instances not tracked by the tracker's open database
71 // list are the ones that have not been added yet, or the ones that we
72 // attempted an open on but failed to. Such instances only exist in the
73 // DatabaseServer's factory methods for creating database backends.
74 //
75 // The factory methods will either call openAndVerifyVersion() or
76 // performOpenAndVerify(). These methods will add the newly instantiated
77 // database backend if they succeed in opening the requested database.
78 // In the case of failure to open the database, the factory methods will
79 // simply discard the newly instantiated database backend when they return.
80 // The ref counting mechanims will automatically destruct the un-added
81 // (and un-returned) databases instances.
82
83 namespace blink {
84
85 static const char versionKey[] = "WebKitDatabaseVersionKey";
86 static const char infoTableName[] = "__WebKitDatabaseInfoTable__";
87
88 static String formatErrorMessage(const char* message, int sqliteErrorCode, const char* sqliteErrorMessage)
89 {
90     return String::format("%s (%d %s)", message, sqliteErrorCode, sqliteErrorMessage);
91 }
92
93 static bool retrieveTextResultFromDatabase(SQLiteDatabase& db, const String& query, String& resultString)
94 {
95     SQLiteStatement statement(db, query);
96     int result = statement.prepare();
97
98     if (result != SQLResultOk) {
99         WTF_LOG_ERROR("Error (%i) preparing statement to read text result from database (%s)", result, query.ascii().data());
100         return false;
101     }
102
103     result = statement.step();
104     if (result == SQLResultRow) {
105         resultString = statement.getColumnText(0);
106         return true;
107     }
108     if (result == SQLResultDone) {
109         resultString = String();
110         return true;
111     }
112
113     WTF_LOG_ERROR("Error (%i) reading text result from database (%s)", result, query.ascii().data());
114     return false;
115 }
116
117 static bool setTextValueInDatabase(SQLiteDatabase& db, const String& query, const String& value)
118 {
119     SQLiteStatement statement(db, query);
120     int result = statement.prepare();
121
122     if (result != SQLResultOk) {
123         WTF_LOG_ERROR("Failed to prepare statement to set value in database (%s)", query.ascii().data());
124         return false;
125     }
126
127     statement.bindText(1, value);
128
129     result = statement.step();
130     if (result != SQLResultDone) {
131         WTF_LOG_ERROR("Failed to step statement to set value in database (%s)", query.ascii().data());
132         return false;
133     }
134
135     return true;
136 }
137
138 // FIXME: move all guid-related functions to a DatabaseVersionTracker class.
139 static RecursiveMutex& guidMutex()
140 {
141     AtomicallyInitializedStatic(RecursiveMutex&, mutex = *new RecursiveMutex);
142     return mutex;
143 }
144
145 typedef HashMap<DatabaseGuid, String> GuidVersionMap;
146 static GuidVersionMap& guidToVersionMap()
147 {
148     // Ensure the the mutex is locked.
149     ASSERT(guidMutex().locked());
150     DEFINE_STATIC_LOCAL(GuidVersionMap, map, ());
151     return map;
152 }
153
154 // NOTE: Caller must lock guidMutex().
155 static inline void updateGuidVersionMap(DatabaseGuid guid, String newVersion)
156 {
157     // Ensure the the mutex is locked.
158     ASSERT(guidMutex().locked());
159
160     // Note: It is not safe to put an empty string into the guidToVersionMap()
161     // map. That's because the map is cross-thread, but empty strings are
162     // per-thread. The copy() function makes a version of the string you can
163     // use on the current thread, but we need a string we can keep in a
164     // cross-thread data structure.
165     // FIXME: This is a quite-awkward restriction to have to program with.
166
167     // Map null string to empty string (see comment above).
168     guidToVersionMap().set(guid, newVersion.isEmpty() ? String() : newVersion.isolatedCopy());
169 }
170
171 typedef HashMap<DatabaseGuid, HashSet<Database*>*> GuidDatabaseMap;
172 static GuidDatabaseMap& guidToDatabaseMap()
173 {
174     // Ensure the the mutex is locked.
175     ASSERT(guidMutex().locked());
176     DEFINE_STATIC_LOCAL(GuidDatabaseMap, map, ());
177     return map;
178 }
179
180 static DatabaseGuid guidForOriginAndName(const String& origin, const String& name)
181 {
182     // Ensure the the mutex is locked.
183     ASSERT(guidMutex().locked());
184
185     String stringID = origin + "/" + name;
186
187     typedef HashMap<String, int> IDGuidMap;
188     DEFINE_STATIC_LOCAL(IDGuidMap, stringIdentifierToGUIDMap, ());
189     DatabaseGuid guid = stringIdentifierToGUIDMap.get(stringID);
190     if (!guid) {
191         static int currentNewGUID = 1;
192         guid = currentNewGUID++;
193         stringIdentifierToGUIDMap.set(stringID, guid);
194     }
195
196     return guid;
197 }
198
199 Database::Database(DatabaseContext* databaseContext, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize)
200     : m_databaseContext(databaseContext)
201     , m_name(name.isolatedCopy())
202     , m_expectedVersion(expectedVersion.isolatedCopy())
203     , m_displayName(displayName.isolatedCopy())
204     , m_estimatedSize(estimatedSize)
205     , m_guid(0)
206     , m_opened(false)
207     , m_new(false)
208     , m_transactionInProgress(false)
209     , m_isTransactionQueueEnabled(true)
210 {
211     m_contextThreadSecurityOrigin = m_databaseContext->securityOrigin()->isolatedCopy();
212
213     m_databaseAuthorizer = DatabaseAuthorizer::create(infoTableName);
214
215     if (m_name.isNull())
216         m_name = "";
217
218     {
219         SafePointAwareMutexLocker locker(guidMutex());
220         m_guid = guidForOriginAndName(securityOrigin()->toString(), name);
221         HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid);
222         if (!hashSet) {
223             hashSet = new HashSet<Database*>;
224             guidToDatabaseMap().set(m_guid, hashSet);
225         }
226
227         hashSet->add(this);
228     }
229
230     m_filename = DatabaseManager::manager().fullPathForDatabase(securityOrigin(), m_name);
231
232     m_databaseThreadSecurityOrigin = m_contextThreadSecurityOrigin->isolatedCopy();
233     ASSERT(m_databaseContext->databaseThread());
234     ASSERT(m_databaseContext->isContextThread());
235 }
236
237 Database::~Database()
238 {
239     // SQLite is "multi-thread safe", but each database handle can only be used
240     // on a single thread at a time.
241     //
242     // For Database, we open the SQLite database on the DatabaseThread, and
243     // hence we should also close it on that same thread. This means that the
244     // SQLite database need to be closed by another mechanism (see
245     // DatabaseContext::stopDatabases()). By the time we get here, the SQLite
246     // database should have already been closed.
247
248     ASSERT(!m_opened);
249 }
250
251 void Database::trace(Visitor* visitor)
252 {
253     visitor->trace(m_databaseContext);
254     visitor->trace(m_sqliteDatabase);
255     visitor->trace(m_databaseAuthorizer);
256     visitor->trace(m_transactionQueue);
257 }
258
259 bool Database::openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage)
260 {
261     TaskSynchronizer synchronizer;
262     if (!databaseContext()->databaseThreadAvailable())
263         return false;
264
265     DatabaseTracker::tracker().prepareToOpenDatabase(this);
266     bool success = false;
267     OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, setVersionInNewDatabase, &synchronizer, error, errorMessage, success);
268     databaseContext()->databaseThread()->scheduleTask(task.release());
269     synchronizer.waitForTaskCompletion();
270
271     return success;
272 }
273
274 void Database::close()
275 {
276     ASSERT(databaseContext()->databaseThread());
277     ASSERT(databaseContext()->databaseThread()->isDatabaseThread());
278
279     {
280         MutexLocker locker(m_transactionInProgressMutex);
281
282         // Clean up transactions that have not been scheduled yet:
283         // Transaction phase 1 cleanup. See comment on "What happens if a
284         // transaction is interrupted?" at the top of SQLTransactionBackend.cpp.
285         SQLTransactionBackend* transaction = nullptr;
286         while (!m_transactionQueue.isEmpty()) {
287             transaction = m_transactionQueue.takeFirst();
288             transaction->notifyDatabaseThreadIsShuttingDown();
289         }
290
291         m_isTransactionQueueEnabled = false;
292         m_transactionInProgress = false;
293     }
294
295     closeDatabase();
296     databaseContext()->databaseThread()->recordDatabaseClosed(this);
297 }
298
299 SQLTransactionBackend* Database::runTransaction(SQLTransaction* transaction, bool readOnly, const ChangeVersionData* data)
300 {
301     MutexLocker locker(m_transactionInProgressMutex);
302     if (!m_isTransactionQueueEnabled)
303         return nullptr;
304
305     SQLTransactionWrapper* wrapper = nullptr;
306     if (data)
307         wrapper = ChangeVersionWrapper::create(data->oldVersion(), data->newVersion());
308
309     SQLTransactionBackend* transactionBackend = SQLTransactionBackend::create(this, transaction, wrapper, readOnly);
310     m_transactionQueue.append(transactionBackend);
311     if (!m_transactionInProgress)
312         scheduleTransaction();
313
314     return transactionBackend;
315 }
316
317 void Database::inProgressTransactionCompleted()
318 {
319     MutexLocker locker(m_transactionInProgressMutex);
320     m_transactionInProgress = false;
321     scheduleTransaction();
322 }
323
324 void Database::scheduleTransaction()
325 {
326     ASSERT(!m_transactionInProgressMutex.tryLock()); // Locked by caller.
327     SQLTransactionBackend* transaction = nullptr;
328
329     if (m_isTransactionQueueEnabled && !m_transactionQueue.isEmpty())
330         transaction = m_transactionQueue.takeFirst();
331
332     if (transaction && databaseContext()->databaseThreadAvailable()) {
333         OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
334         WTF_LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for transaction %p\n", task.get(), task->transaction());
335         m_transactionInProgress = true;
336         databaseContext()->databaseThread()->scheduleTask(task.release());
337     } else {
338         m_transactionInProgress = false;
339     }
340 }
341
342 void Database::scheduleTransactionStep(SQLTransactionBackend* transaction)
343 {
344     if (!databaseContext()->databaseThreadAvailable())
345         return;
346
347     OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction);
348     WTF_LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task.get());
349     databaseContext()->databaseThread()->scheduleTask(task.release());
350 }
351
352 SQLTransactionClient* Database::transactionClient() const
353 {
354     return databaseContext()->databaseThread()->transactionClient();
355 }
356
357 SQLTransactionCoordinator* Database::transactionCoordinator() const
358 {
359     return databaseContext()->databaseThread()->transactionCoordinator();
360 }
361
362 // static
363 const char* Database::databaseInfoTableName()
364 {
365     return infoTableName;
366 }
367
368 void Database::closeDatabase()
369 {
370     if (!m_opened)
371         return;
372
373     m_sqliteDatabase.close();
374     m_opened = false;
375     // See comment at the top this file regarding calling removeOpenDatabase().
376     DatabaseTracker::tracker().removeOpenDatabase(this);
377     {
378         SafePointAwareMutexLocker locker(guidMutex());
379
380         HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid);
381         ASSERT(hashSet);
382         ASSERT(hashSet->contains(this));
383         hashSet->remove(this);
384         if (hashSet->isEmpty()) {
385             guidToDatabaseMap().remove(m_guid);
386             delete hashSet;
387             guidToVersionMap().remove(m_guid);
388         }
389     }
390 }
391
392 String Database::version() const
393 {
394     // Note: In multi-process browsers the cached value may be accurate, but we
395     // cannot read the actual version from the database without potentially
396     // inducing a deadlock.
397     // FIXME: Add an async version getter to the DatabaseAPI.
398     return getCachedVersion();
399 }
400
401 class DoneCreatingDatabaseOnExitCaller {
402     STACK_ALLOCATED();
403 public:
404     DoneCreatingDatabaseOnExitCaller(Database* database)
405         : m_database(database)
406         , m_openSucceeded(false)
407     {
408     }
409     ~DoneCreatingDatabaseOnExitCaller()
410     {
411         if (!m_openSucceeded)
412             DatabaseTracker::tracker().failedToOpenDatabase(m_database);
413     }
414
415     void setOpenSucceeded() { m_openSucceeded = true; }
416
417 private:
418     Member<Database> m_database;
419     bool m_openSucceeded;
420 };
421
422 bool Database::performOpenAndVerify(bool shouldSetVersionInNewDatabase, DatabaseError& error, String& errorMessage)
423 {
424     DoneCreatingDatabaseOnExitCaller onExitCaller(this);
425     ASSERT(errorMessage.isEmpty());
426     ASSERT(error == DatabaseError::None); // Better not have any errors already.
427     // Presumed failure. We'll clear it if we succeed below.
428     error = DatabaseError::InvalidDatabaseState;
429
430     const int maxSqliteBusyWaitTime = 30000;
431
432     if (!m_sqliteDatabase.open(m_filename)) {
433         reportOpenDatabaseResult(1, InvalidStateError, m_sqliteDatabase.lastError());
434         errorMessage = formatErrorMessage("unable to open database", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
435         return false;
436     }
437     if (!m_sqliteDatabase.turnOnIncrementalAutoVacuum())
438         WTF_LOG_ERROR("Unable to turn on incremental auto-vacuum (%d %s)", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
439
440     m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime);
441
442     String currentVersion;
443     {
444         SafePointAwareMutexLocker locker(guidMutex());
445
446         GuidVersionMap::iterator entry = guidToVersionMap().find(m_guid);
447         if (entry != guidToVersionMap().end()) {
448             // Map null string to empty string (see updateGuidVersionMap()).
449             currentVersion = entry->value.isNull() ? emptyString() : entry->value.isolatedCopy();
450             WTF_LOG(StorageAPI, "Current cached version for guid %i is %s", m_guid, currentVersion.ascii().data());
451
452             // Note: In multi-process browsers the cached value may be
453             // inaccurate, but we cannot read the actual version from the
454             // database without potentially inducing a form of deadlock, a
455             // busytimeout error when trying to access the database. So we'll
456             // use the cached value if we're unable to read the value from the
457             // database file without waiting.
458             // FIXME: Add an async openDatabase method to the DatabaseAPI.
459             const int noSqliteBusyWaitTime = 0;
460             m_sqliteDatabase.setBusyTimeout(noSqliteBusyWaitTime);
461             String versionFromDatabase;
462             if (getVersionFromDatabase(versionFromDatabase, false)) {
463                 currentVersion = versionFromDatabase;
464                 updateGuidVersionMap(m_guid, currentVersion);
465             }
466             m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime);
467         } else {
468             WTF_LOG(StorageAPI, "No cached version for guid %i", m_guid);
469
470             SQLiteTransaction transaction(m_sqliteDatabase);
471             transaction.begin();
472             if (!transaction.inProgress()) {
473                 reportOpenDatabaseResult(2, InvalidStateError, m_sqliteDatabase.lastError());
474                 errorMessage = formatErrorMessage("unable to open database, failed to start transaction", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
475                 m_sqliteDatabase.close();
476                 return false;
477             }
478
479             String tableName(infoTableName);
480             if (!m_sqliteDatabase.tableExists(tableName)) {
481                 m_new = true;
482
483                 if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + tableName + " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value TEXT NOT NULL ON CONFLICT FAIL);")) {
484                     reportOpenDatabaseResult(3, InvalidStateError, m_sqliteDatabase.lastError());
485                     errorMessage = formatErrorMessage("unable to open database, failed to create 'info' table", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
486                     transaction.rollback();
487                     m_sqliteDatabase.close();
488                     return false;
489                 }
490             } else if (!getVersionFromDatabase(currentVersion, false)) {
491                 reportOpenDatabaseResult(4, InvalidStateError, m_sqliteDatabase.lastError());
492                 errorMessage = formatErrorMessage("unable to open database, failed to read current version", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
493                 transaction.rollback();
494                 m_sqliteDatabase.close();
495                 return false;
496             }
497
498             if (currentVersion.length()) {
499                 WTF_LOG(StorageAPI, "Retrieved current version %s from database %s", currentVersion.ascii().data(), databaseDebugName().ascii().data());
500             } else if (!m_new || shouldSetVersionInNewDatabase) {
501                 WTF_LOG(StorageAPI, "Setting version %s in database %s that was just created", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data());
502                 if (!setVersionInDatabase(m_expectedVersion, false)) {
503                     reportOpenDatabaseResult(5, InvalidStateError, m_sqliteDatabase.lastError());
504                     errorMessage = formatErrorMessage("unable to open database, failed to write current version", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg());
505                     transaction.rollback();
506                     m_sqliteDatabase.close();
507                     return false;
508                 }
509                 currentVersion = m_expectedVersion;
510             }
511             updateGuidVersionMap(m_guid, currentVersion);
512             transaction.commit();
513         }
514     }
515
516     if (currentVersion.isNull()) {
517         WTF_LOG(StorageAPI, "Database %s does not have its version set", databaseDebugName().ascii().data());
518         currentVersion = "";
519     }
520
521     // If the expected version isn't the empty string, ensure that the current
522     // database version we have matches that version. Otherwise, set an
523     // exception.
524     // If the expected version is the empty string, then we always return with
525     // whatever version of the database we have.
526     if ((!m_new || shouldSetVersionInNewDatabase) && m_expectedVersion.length() && m_expectedVersion != currentVersion) {
527         reportOpenDatabaseResult(6, InvalidStateError, 0);
528         errorMessage = "unable to open database, version mismatch, '" + m_expectedVersion + "' does not match the currentVersion of '" + currentVersion + "'";
529         m_sqliteDatabase.close();
530         return false;
531     }
532
533     ASSERT(m_databaseAuthorizer);
534     m_sqliteDatabase.setAuthorizer(m_databaseAuthorizer.get());
535
536     // See comment at the top this file regarding calling addOpenDatabase().
537     DatabaseTracker::tracker().addOpenDatabase(this);
538     m_opened = true;
539
540     // Declare success:
541     error = DatabaseError::None; // Clear the presumed error from above.
542     onExitCaller.setOpenSucceeded();
543
544     if (m_new && !shouldSetVersionInNewDatabase) {
545         // The caller provided a creationCallback which will set the expected
546         // version.
547         m_expectedVersion = "";
548     }
549
550     reportOpenDatabaseResult(0, -1, 0); // OK
551
552     if (databaseContext()->databaseThread())
553         databaseContext()->databaseThread()->recordDatabaseOpen(this);
554     return true;
555 }
556
557 String Database::stringIdentifier() const
558 {
559     // Return a deep copy for ref counting thread safety
560     return m_name.isolatedCopy();
561 }
562
563 String Database::displayName() const
564 {
565     // Return a deep copy for ref counting thread safety
566     return m_displayName.isolatedCopy();
567 }
568
569 unsigned long Database::estimatedSize() const
570 {
571     return m_estimatedSize;
572 }
573
574 String Database::fileName() const
575 {
576     // Return a deep copy for ref counting thread safety
577     return m_filename.isolatedCopy();
578 }
579
580 bool Database::getVersionFromDatabase(String& version, bool shouldCacheVersion)
581 {
582     String query(String("SELECT value FROM ") + infoTableName +  " WHERE key = '" + versionKey + "';");
583
584     m_databaseAuthorizer->disable();
585
586     bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, query, version);
587     if (result) {
588         if (shouldCacheVersion)
589             setCachedVersion(version);
590     } else {
591         WTF_LOG_ERROR("Failed to retrieve version from database %s", databaseDebugName().ascii().data());
592     }
593
594     m_databaseAuthorizer->enable();
595
596     return result;
597 }
598
599 bool Database::setVersionInDatabase(const String& version, bool shouldCacheVersion)
600 {
601     // The INSERT will replace an existing entry for the database with the new
602     // version number, due to the UNIQUE ON CONFLICT REPLACE clause in the
603     // CREATE statement (see Database::performOpenAndVerify()).
604     String query(String("INSERT INTO ") + infoTableName +  " (key, value) VALUES ('" + versionKey + "', ?);");
605
606     m_databaseAuthorizer->disable();
607
608     bool result = setTextValueInDatabase(m_sqliteDatabase, query, version);
609     if (result) {
610         if (shouldCacheVersion)
611             setCachedVersion(version);
612     } else {
613         WTF_LOG_ERROR("Failed to set version %s in database (%s)", version.ascii().data(), query.ascii().data());
614     }
615
616     m_databaseAuthorizer->enable();
617
618     return result;
619 }
620
621 void Database::setExpectedVersion(const String& version)
622 {
623     m_expectedVersion = version.isolatedCopy();
624 }
625
626 String Database::getCachedVersion() const
627 {
628     SafePointAwareMutexLocker locker(guidMutex());
629     return guidToVersionMap().get(m_guid).isolatedCopy();
630 }
631
632 void Database::setCachedVersion(const String& actualVersion)
633 {
634     // Update the in memory database version map.
635     SafePointAwareMutexLocker locker(guidMutex());
636     updateGuidVersionMap(m_guid, actualVersion);
637 }
638
639 bool Database::getActualVersionForTransaction(String& actualVersion)
640 {
641     ASSERT(m_sqliteDatabase.transactionInProgress());
642     // Note: In multi-process browsers the cached value may be inaccurate. So we
643     // retrieve the value from the database and update the cached value here.
644     return getVersionFromDatabase(actualVersion, true);
645 }
646
647 void Database::disableAuthorizer()
648 {
649     ASSERT(m_databaseAuthorizer);
650     m_databaseAuthorizer->disable();
651 }
652
653 void Database::enableAuthorizer()
654 {
655     ASSERT(m_databaseAuthorizer);
656     m_databaseAuthorizer->enable();
657 }
658
659 void Database::setAuthorizerPermissions(int permissions)
660 {
661     ASSERT(m_databaseAuthorizer);
662     m_databaseAuthorizer->setPermissions(permissions);
663 }
664
665 bool Database::lastActionChangedDatabase()
666 {
667     ASSERT(m_databaseAuthorizer);
668     return m_databaseAuthorizer->lastActionChangedDatabase();
669 }
670
671 bool Database::lastActionWasInsert()
672 {
673     ASSERT(m_databaseAuthorizer);
674     return m_databaseAuthorizer->lastActionWasInsert();
675 }
676
677 void Database::resetDeletes()
678 {
679     ASSERT(m_databaseAuthorizer);
680     m_databaseAuthorizer->resetDeletes();
681 }
682
683 bool Database::hadDeletes()
684 {
685     ASSERT(m_databaseAuthorizer);
686     return m_databaseAuthorizer->hadDeletes();
687 }
688
689 void Database::resetAuthorizer()
690 {
691     if (m_databaseAuthorizer)
692         m_databaseAuthorizer->reset();
693 }
694
695 unsigned long long Database::maximumSize() const
696 {
697     return DatabaseTracker::tracker().getMaxSizeForDatabase(this);
698 }
699
700 void Database::incrementalVacuumIfNeeded()
701 {
702     int64_t freeSpaceSize = m_sqliteDatabase.freeSpaceSize();
703     int64_t totalSize = m_sqliteDatabase.totalSize();
704     if (totalSize <= 10 * freeSpaceSize) {
705         int result = m_sqliteDatabase.runIncrementalVacuumCommand();
706         reportVacuumDatabaseResult(result);
707         if (result != SQLResultOk)
708             logErrorMessage(formatErrorMessage("error vacuuming database", result, m_sqliteDatabase.lastErrorMsg()));
709     }
710 }
711
712 // These are used to generate histograms of errors seen with websql.
713 // See about:histograms in chromium.
714 void Database::reportOpenDatabaseResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode)
715 {
716     if (Platform::current()->databaseObserver()) {
717         Platform::current()->databaseObserver()->reportOpenDatabaseResult(
718             createDatabaseIdentifierFromSecurityOrigin(securityOrigin()),
719             stringIdentifier(), errorSite, webSqlErrorCode, sqliteErrorCode);
720     }
721 }
722
723 void Database::reportChangeVersionResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode)
724 {
725     if (Platform::current()->databaseObserver()) {
726         Platform::current()->databaseObserver()->reportChangeVersionResult(
727             createDatabaseIdentifierFromSecurityOrigin(securityOrigin()),
728             stringIdentifier(), errorSite, webSqlErrorCode, sqliteErrorCode);
729     }
730 }
731
732 void Database::reportStartTransactionResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode)
733 {
734     if (Platform::current()->databaseObserver()) {
735         Platform::current()->databaseObserver()->reportStartTransactionResult(
736             createDatabaseIdentifierFromSecurityOrigin(securityOrigin()),
737             stringIdentifier(), errorSite, webSqlErrorCode, sqliteErrorCode);
738     }
739 }
740
741 void Database::reportCommitTransactionResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode)
742 {
743     if (Platform::current()->databaseObserver()) {
744         Platform::current()->databaseObserver()->reportCommitTransactionResult(
745             createDatabaseIdentifierFromSecurityOrigin(securityOrigin()),
746             stringIdentifier(), errorSite, webSqlErrorCode, sqliteErrorCode);
747     }
748 }
749
750 void Database::reportExecuteStatementResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode)
751 {
752     if (Platform::current()->databaseObserver()) {
753         Platform::current()->databaseObserver()->reportExecuteStatementResult(
754             createDatabaseIdentifierFromSecurityOrigin(securityOrigin()),
755             stringIdentifier(), errorSite, webSqlErrorCode, sqliteErrorCode);
756     }
757 }
758
759 void Database::reportVacuumDatabaseResult(int sqliteErrorCode)
760 {
761     if (Platform::current()->databaseObserver()) {
762         Platform::current()->databaseObserver()->reportVacuumDatabaseResult(
763             createDatabaseIdentifierFromSecurityOrigin(securityOrigin()),
764             stringIdentifier(), sqliteErrorCode);
765     }
766 }
767
768 void Database::logErrorMessage(const String& message)
769 {
770     executionContext()->addConsoleMessage(ConsoleMessage::create(StorageMessageSource, ErrorMessageLevel, message));
771 }
772
773 ExecutionContext* Database::executionContext() const
774 {
775     return databaseContext()->executionContext();
776 }
777
778 void Database::closeImmediately()
779 {
780     ASSERT(executionContext()->isContextThread());
781     if (databaseContext()->databaseThreadAvailable() && opened()) {
782         logErrorMessage("forcibly closing database");
783         databaseContext()->databaseThread()->scheduleTask(DatabaseCloseTask::create(this, 0));
784     }
785 }
786
787 void Database::changeVersion(
788     const String& oldVersion,
789     const String& newVersion,
790     SQLTransactionCallback* callback,
791     SQLTransactionErrorCallback* errorCallback,
792     VoidCallback* successCallback)
793 {
794     ChangeVersionData data(oldVersion, newVersion);
795     runTransaction(callback, errorCallback, successCallback, false, &data);
796 }
797
798 void Database::transaction(
799     SQLTransactionCallback* callback,
800     SQLTransactionErrorCallback* errorCallback,
801     VoidCallback* successCallback)
802 {
803     runTransaction(callback, errorCallback, successCallback, false);
804 }
805
806 void Database::readTransaction(
807     SQLTransactionCallback* callback,
808     SQLTransactionErrorCallback* errorCallback,
809     VoidCallback* successCallback)
810 {
811     runTransaction(callback, errorCallback, successCallback, true);
812 }
813
814 static void callTransactionErrorCallback(ExecutionContext*, SQLTransactionErrorCallback* callback, PassOwnPtr<SQLErrorData> errorData)
815 {
816     callback->handleEvent(SQLError::create(*errorData));
817 }
818
819 void Database::runTransaction(
820     SQLTransactionCallback* callback,
821     SQLTransactionErrorCallback* errorCallback,
822     VoidCallback* successCallback,
823     bool readOnly,
824     const ChangeVersionData* changeVersionData)
825 {
826     // FIXME: Rather than passing errorCallback to SQLTransaction and then
827     // sometimes firing it ourselves, this code should probably be pushed down
828     // into Database so that we only create the SQLTransaction if we're
829     // actually going to run it.
830 #if ENABLE(ASSERT)
831     SQLTransactionErrorCallback* originalErrorCallback = errorCallback;
832 #endif
833     SQLTransaction* transaction = SQLTransaction::create(this, callback, successCallback, errorCallback, readOnly);
834     SQLTransactionBackend* transactionBackend = runTransaction(transaction, readOnly, changeVersionData);
835     if (!transactionBackend) {
836         SQLTransactionErrorCallback* callback = transaction->releaseErrorCallback();
837         ASSERT(callback == originalErrorCallback);
838         if (callback) {
839             OwnPtr<SQLErrorData> error = SQLErrorData::create(SQLError::UNKNOWN_ERR, "database has been closed");
840             executionContext()->postTask(createCrossThreadTask(&callTransactionErrorCallback, callback, error.release()));
841         }
842     }
843 }
844
845 // This object is constructed in a database thread, and destructed in the
846 // context thread.
847 class DeliverPendingCallbackTask final : public ExecutionContextTask {
848 public:
849     static PassOwnPtr<DeliverPendingCallbackTask> create(SQLTransaction* transaction)
850     {
851         return adoptPtr(new DeliverPendingCallbackTask(transaction));
852     }
853
854     virtual void performTask(ExecutionContext*) override
855     {
856         m_transaction->performPendingCallback();
857     }
858
859 private:
860     DeliverPendingCallbackTask(SQLTransaction* transaction)
861         : m_transaction(transaction)
862     {
863     }
864
865     CrossThreadPersistent<SQLTransaction> m_transaction;
866 };
867
868 void Database::scheduleTransactionCallback(SQLTransaction* transaction)
869 {
870     executionContext()->postTask(DeliverPendingCallbackTask::create(transaction));
871 }
872
873 Vector<String> Database::performGetTableNames()
874 {
875     disableAuthorizer();
876
877     SQLiteStatement statement(sqliteDatabase(), "SELECT name FROM sqlite_master WHERE type='table';");
878     if (statement.prepare() != SQLResultOk) {
879         WTF_LOG_ERROR("Unable to retrieve list of tables for database %s", databaseDebugName().ascii().data());
880         enableAuthorizer();
881         return Vector<String>();
882     }
883
884     Vector<String> tableNames;
885     int result;
886     while ((result = statement.step()) == SQLResultRow) {
887         String name = statement.getColumnText(0);
888         if (name != databaseInfoTableName())
889             tableNames.append(name);
890     }
891
892     enableAuthorizer();
893
894     if (result != SQLResultDone) {
895         WTF_LOG_ERROR("Error getting tables for database %s", databaseDebugName().ascii().data());
896         return Vector<String>();
897     }
898
899     return tableNames;
900 }
901
902 Vector<String> Database::tableNames()
903 {
904     // FIXME: Not using isolatedCopy on these strings looks ok since threads
905     // take strict turns in dealing with them. However, if the code changes,
906     // this may not be true anymore.
907     Vector<String> result;
908     TaskSynchronizer synchronizer;
909     if (!databaseContext()->databaseThreadAvailable())
910         return result;
911
912     OwnPtr<DatabaseTableNamesTask> task = DatabaseTableNamesTask::create(this, &synchronizer, result);
913     databaseContext()->databaseThread()->scheduleTask(task.release());
914     synchronizer.waitForTaskCompletion();
915
916     return result;
917 }
918
919 SecurityOrigin* Database::securityOrigin() const
920 {
921     if (executionContext()->isContextThread())
922         return m_contextThreadSecurityOrigin.get();
923     if (databaseContext()->databaseThread()->isDatabaseThread())
924         return m_databaseThreadSecurityOrigin.get();
925     return 0;
926 }
927
928 } // namespace blink