blob: ca59f17642b0d90f0edccfb8835789f7589828e1 [file] [log] [blame]
/*
* Copyright (C) 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "DatabaseTracker.h"
#include "Database.h"
#include "FileSystem.h"
#include "NotImplemented.h"
#include "SQLiteStatement.h"
namespace WebCore {
DatabaseTracker& DatabaseTracker::tracker()
{
static DatabaseTracker tracker;
return tracker;
}
DatabaseTracker::DatabaseTracker()
{
}
void DatabaseTracker::setDatabasePath(const String& path)
{
m_databasePath = path;
openTrackerDatabase();
}
const String& DatabaseTracker::databasePath()
{
return m_databasePath;
}
void DatabaseTracker::openTrackerDatabase()
{
ASSERT(!m_database.isOpen());
makeAllDirectories(m_databasePath);
String databasePath = pathByAppendingComponent(m_databasePath, "Databases.db");
if (!m_database.open(databasePath)) {
// FIXME: What do do here?
return;
}
if (!m_database.tableExists("Origins")) {
if (!m_database.executeCommand("CREATE TABLE Origins (origin TEXT UNIQUE ON CONFLICT REPLACE, creationPolicy INTEGER NOT NULL ON CONFLICT FAIL, sizePolicy INTEGER NOT NULL ON CONFLICT FAIL);")) {
// FIXME: and here
}
}
if (!m_database.tableExists("Databases")) {
if (!m_database.executeCommand("CREATE TABLE Databases (guid INTEGER PRIMARY KEY AUTOINCREMENT, origin TEXT UNIQUE ON CONFLICT REPLACE, name TEXT UNIQUE ON CONFLICT REPLACE, path TEXT NOT NULL ON CONFLICT FAIL);")) {
// FIXME: and here
}
}
}
String DatabaseTracker::fullPathForDatabase(const String& origin, const String& name)
{
SQLiteStatement statement(m_database, "SELECT path FROM Databases WHERE origin=? AND name=?;");
if (statement.prepare() != SQLResultOk)
return "";
statement.bindText16(1, origin, false);
statement.bindText16(2, name, false);
int result = statement.step();
if (result == SQLResultRow)
return pathByAppendingComponent(m_databasePath, statement.getColumnText16(0));
if (result != SQLResultDone) {
LOG_ERROR("Failed to retrieve filename from Database Tracker for origin %s, name %s", origin.ascii().data(), name.ascii().data());
return "";
}
SQLiteStatement sequenceStatement(m_database, "SELECT seq FROM sqlite_sequence WHERE name='Databases';");
// FIXME: More informative error handling here, even though these steps should never fail
if (sequenceStatement.prepare() != SQLResultOk)
return "";
result = sequenceStatement.step();
// This has a range of 2^63 and starts at 0 for every time a user resets Safari -
// I can't imagine it'd over overflow
int64_t seq = 0;
if (result == SQLResultRow) {
seq = sequenceStatement.getColumnInt64(0);
} else if (result != SQLResultDone)
return "";
String filename;
do {
++seq;
filename = pathByAppendingComponent(m_databasePath, String::format("%016llx.db", seq));
} while (fileExists(filename));
sequenceStatement.finalize();
if (!addDatabase(origin, name, String::format("%016llx.db", seq)))
return "";
return filename;
}
void DatabaseTracker::populateOrigins()
{
if (m_origins)
return;
m_origins.set(new HashSet<String>);
if (!m_database.isOpen())
return;
SQLiteStatement statement(m_database, "SELECT DISTINCT origin FROM Databases;");
if (statement.prepare() != SQLResultOk)
return;
int result;
while ((result = statement.step()) == SQLResultRow)
m_origins->add(statement.getColumnText16(0));
if (result != SQLResultDone)
LOG_ERROR("Failed to read in all origins from the database");
return;
}
const HashSet<String>& DatabaseTracker::origins()
{
if (!m_origins)
populateOrigins();
return *(m_origins.get());
}
bool DatabaseTracker::databaseNamesForOrigin(const String& origin, Vector<String>& resultVector)
{
if (!m_database.isOpen())
return false;
SQLiteStatement statement(m_database, "SELECT name FROM Databases where origin=?;");
if (statement.prepare() != SQLResultOk)
return false;
statement.bindText16(1, origin, false);
int result;
while ((result = statement.step()) == SQLResultRow)
resultVector.append(statement.getColumnText16(0));
if (result != SQLResultDone) {
LOG_ERROR("Failed to retrieve all database names for origin %s", origin.ascii().data());
return false;
}
return true;
}
bool DatabaseTracker::addDatabase(const String& origin, const String& name, const String& path)
{
if (!m_database.isOpen())
return false;
SQLiteStatement statement(m_database, "INSERT INTO Databases (origin, name, path) VALUES (?, ?, ?);");
if (statement.prepare() != SQLResultOk)
return false;
statement.bindText16(1, origin, true);
statement.bindText16(2, name, true);
statement.bindText16(3, path, true);
if (!statement.executeCommand()) {
LOG_ERROR("Failed to add database %s to origin %s: %s\n", name.ascii().data(), origin.ascii().data(), statement.lastErrorMsg());
return false;
}
populateOrigins();
m_origins->add(origin);
return true;
}
void DatabaseTracker::deleteAllDatabases()
{
notImplemented();
}
void DatabaseTracker::deleteAllDatabasesForOrigin(const String& origin)
{
notImplemented();
}
void DatabaseTracker::deleteDatabase(const String& origin, const String& name)
{
notImplemented();
}
} // namespace WebCore