Changeset 80220 in webkit


Ignore:
Timestamp:
Mar 3, 2011 2:37:41 AM (13 years ago)
Author:
hans@chromium.org
Message:

2011-03-03 Hans Wennborg <hans@chromium.org>

Reviewed by Jeremy Orlow.

IndexedDB: Move SQL code, especially for cursors, to IDBBackingStore
https://bugs.webkit.org/show_bug.cgi?id=55376

Move SQL code from IDBKey, IDBKeyRange, IDBIndexBackendImpl,
IDBObjectStoreBackendImpl, and especially IDBCursorBackendImpl.

No new functionality, so no new tests.

  • storage/IDBBackingStore.cpp: (WebCore::lowerCursorWhereFragment): (WebCore::upperCursorWhereFragment): (WebCore::IDBBackingStore::deleteObjectStoreRecord): (WebCore::IDBBackingStore::keyExistsInObjectStore): (WebCore::IDBBackingStore::getObjectViaIndex): (WebCore::keyFromQuery): (WebCore::IDBBackingStore::getPrimaryKeyViaIndex): (WebCore::IDBBackingStore::keyExistsInIndex): (WebCore::CursorImplCommon::CursorImplCommon::continueInternal): (WebCore::CursorImplCommon::ObjectStoreCursorImpl::ObjectStoreCursorImpl): (WebCore::CursorImplCommon::ObjectStoreCursorImpl::objectStoreDataId): (WebCore::CursorImplCommon::ObjectStoreCursorImpl::key): (WebCore::CursorImplCommon::ObjectStoreCursorImpl::value): (WebCore::CursorImplCommon::ObjectStoreCursorImpl::continueFunction): (WebCore::IDBBackingStore::openObjectStoreCursor): (WebCore::ObjectStoreCursorImpl::loadCurrentRow): (WebCore::ObjectStoreCursorImpl::currentRowExists): (WebCore::IndexKeyCursorImpl::IndexKeyCursorImpl): (WebCore::IndexKeyCursorImpl::indexDataId): (WebCore::IndexKeyCursorImpl::key): (WebCore::IndexKeyCursorImpl::primaryKey): (WebCore::IndexKeyCursorImpl::continueFunction): (WebCore::IDBBackingStore::openIndexKeyCursor): (WebCore::IndexKeyCursorImpl::loadCurrentRow): (WebCore::IndexKeyCursorImpl::currentRowExists): (WebCore::IndexCursorImpl::IndexCursorImpl): (WebCore::IndexCursorImpl::indexDataId): (WebCore::IndexCursorImpl::key): (WebCore::IndexCursorImpl::primaryKey): (WebCore::IndexCursorImpl::value): (WebCore::IndexCursorImpl::continueFunction): (WebCore::IDBBackingStore::openIndexCursor): (WebCore::IndexCursorImpl::loadCurrentRow): (WebCore::IndexCursorImpl::currentRowExists):
  • storage/IDBBackingStore.h: (WebCore::IDBBackingStore::Cursor::~Cursor):
  • storage/IDBCursorBackendImpl.cpp: (WebCore::IDBCursorBackendImpl::IDBCursorBackendImpl): (WebCore::IDBCursorBackendImpl::key): (WebCore::IDBCursorBackendImpl::value): (WebCore::IDBCursorBackendImpl::update): (WebCore::IDBCursorBackendImpl::continueFunctionInternal): (WebCore::IDBCursorBackendImpl::deleteFunction):
  • storage/IDBCursorBackendImpl.h: (WebCore::IDBCursorBackendImpl::create):
  • storage/IDBIndexBackendImpl.cpp: (WebCore::IDBIndexBackendImpl::openCursorInternal): (WebCore::IDBIndexBackendImpl::getInternal): (WebCore::IDBIndexBackendImpl::addingKeyAllowed):
  • storage/IDBIndexBackendImpl.h:
  • storage/IDBKey.cpp: (WebCore::IDBKey::isEqual):
  • storage/IDBKey.h:
  • storage/IDBKeyRange.cpp:
  • storage/IDBKeyRange.h:
  • storage/IDBObjectStoreBackendImpl.cpp: (WebCore::IDBObjectStoreBackendImpl::putInternal): (WebCore::IDBObjectStoreBackendImpl::deleteInternal): (WebCore::IDBObjectStoreBackendImpl::openCursorInternal):
  • storage/IDBObjectStoreBackendImpl.h:
Location:
trunk/Source/WebCore
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r80218 r80220  
     12011-03-03  Hans Wennborg  <hans@chromium.org>
     2
     3        Reviewed by Jeremy Orlow.
     4
     5        IndexedDB: Move SQL code, especially for cursors, to IDBBackingStore
     6        https://bugs.webkit.org/show_bug.cgi?id=55376
     7
     8        Move SQL code from IDBKey, IDBKeyRange, IDBIndexBackendImpl,
     9        IDBObjectStoreBackendImpl, and especially IDBCursorBackendImpl.
     10
     11        No new functionality, so no new tests.
     12
     13        * storage/IDBBackingStore.cpp:
     14        (WebCore::lowerCursorWhereFragment):
     15        (WebCore::upperCursorWhereFragment):
     16        (WebCore::IDBBackingStore::deleteObjectStoreRecord):
     17        (WebCore::IDBBackingStore::keyExistsInObjectStore):
     18        (WebCore::IDBBackingStore::getObjectViaIndex):
     19        (WebCore::keyFromQuery):
     20        (WebCore::IDBBackingStore::getPrimaryKeyViaIndex):
     21        (WebCore::IDBBackingStore::keyExistsInIndex):
     22        (WebCore::CursorImplCommon::CursorImplCommon::continueInternal):
     23        (WebCore::CursorImplCommon::ObjectStoreCursorImpl::ObjectStoreCursorImpl):
     24        (WebCore::CursorImplCommon::ObjectStoreCursorImpl::objectStoreDataId):
     25        (WebCore::CursorImplCommon::ObjectStoreCursorImpl::key):
     26        (WebCore::CursorImplCommon::ObjectStoreCursorImpl::value):
     27        (WebCore::CursorImplCommon::ObjectStoreCursorImpl::continueFunction):
     28        (WebCore::IDBBackingStore::openObjectStoreCursor):
     29        (WebCore::ObjectStoreCursorImpl::loadCurrentRow):
     30        (WebCore::ObjectStoreCursorImpl::currentRowExists):
     31        (WebCore::IndexKeyCursorImpl::IndexKeyCursorImpl):
     32        (WebCore::IndexKeyCursorImpl::indexDataId):
     33        (WebCore::IndexKeyCursorImpl::key):
     34        (WebCore::IndexKeyCursorImpl::primaryKey):
     35        (WebCore::IndexKeyCursorImpl::continueFunction):
     36        (WebCore::IDBBackingStore::openIndexKeyCursor):
     37        (WebCore::IndexKeyCursorImpl::loadCurrentRow):
     38        (WebCore::IndexKeyCursorImpl::currentRowExists):
     39        (WebCore::IndexCursorImpl::IndexCursorImpl):
     40        (WebCore::IndexCursorImpl::indexDataId):
     41        (WebCore::IndexCursorImpl::key):
     42        (WebCore::IndexCursorImpl::primaryKey):
     43        (WebCore::IndexCursorImpl::value):
     44        (WebCore::IndexCursorImpl::continueFunction):
     45        (WebCore::IDBBackingStore::openIndexCursor):
     46        (WebCore::IndexCursorImpl::loadCurrentRow):
     47        (WebCore::IndexCursorImpl::currentRowExists):
     48        * storage/IDBBackingStore.h:
     49        (WebCore::IDBBackingStore::Cursor::~Cursor):
     50        * storage/IDBCursorBackendImpl.cpp:
     51        (WebCore::IDBCursorBackendImpl::IDBCursorBackendImpl):
     52        (WebCore::IDBCursorBackendImpl::key):
     53        (WebCore::IDBCursorBackendImpl::value):
     54        (WebCore::IDBCursorBackendImpl::update):
     55        (WebCore::IDBCursorBackendImpl::continueFunctionInternal):
     56        (WebCore::IDBCursorBackendImpl::deleteFunction):
     57        * storage/IDBCursorBackendImpl.h:
     58        (WebCore::IDBCursorBackendImpl::create):
     59        * storage/IDBIndexBackendImpl.cpp:
     60        (WebCore::IDBIndexBackendImpl::openCursorInternal):
     61        (WebCore::IDBIndexBackendImpl::getInternal):
     62        (WebCore::IDBIndexBackendImpl::addingKeyAllowed):
     63        * storage/IDBIndexBackendImpl.h:
     64        * storage/IDBKey.cpp:
     65        (WebCore::IDBKey::isEqual):
     66        * storage/IDBKey.h:
     67        * storage/IDBKeyRange.cpp:
     68        * storage/IDBKeyRange.h:
     69        * storage/IDBObjectStoreBackendImpl.cpp:
     70        (WebCore::IDBObjectStoreBackendImpl::putInternal):
     71        (WebCore::IDBObjectStoreBackendImpl::deleteInternal):
     72        (WebCore::IDBObjectStoreBackendImpl::openCursorInternal):
     73        * storage/IDBObjectStoreBackendImpl.h:
     74
    1752011-03-03  Peter Kasting  <pkasting@google.com>
    276
  • trunk/Source/WebCore/storage/IDBBackingStore.cpp

    r79445 r80220  
    3232#include "IDBFactoryBackendImpl.h"
    3333#include "IDBKey.h"
     34#include "IDBKeyRange.h"
    3435#include "SQLiteDatabase.h"
    3536#include "SQLiteStatement.h"
     
    335336    ASSERT_NOT_REACHED();
    336337    return 0;
     338}
     339
     340static String lowerCursorWhereFragment(const IDBKey& key, String comparisonOperator, String qualifiedTableName = "")
     341{
     342    switch (key.type()) {
     343    case IDBKey::StringType:
     344        return "? " + comparisonOperator + " " + qualifiedTableName + "keyString  AND  ";
     345    case IDBKey::DateType:
     346        return "(? " + comparisonOperator + " " + qualifiedTableName + "keyDate  OR NOT " + qualifiedTableName + "keyString IS NULL)  AND  ";
     347    case IDBKey::NumberType:
     348        return "(? " + comparisonOperator + " " + qualifiedTableName + "keyNumber  OR  NOT " + qualifiedTableName + "keyString IS NULL  OR  NOT " + qualifiedTableName + "keyDate IS NULL)  AND  ";
     349    case IDBKey::NullType:
     350        if (comparisonOperator == "<")
     351            return "NOT(" + qualifiedTableName + "keyString IS NULL  AND  " + qualifiedTableName + "keyDate IS NULL  AND  " + qualifiedTableName + "keyNumber IS NULL)  AND  ";
     352        return ""; // If it's =, the upper bound half will do the constraining. If it's <=, then that's a no-op.
     353    }
     354    ASSERT_NOT_REACHED();
     355    return "";
     356}
     357
     358static String upperCursorWhereFragment(const IDBKey& key, String comparisonOperator, String qualifiedTableName = "")
     359{
     360    switch (key.type()) {
     361    case IDBKey::StringType:
     362        return "(" + qualifiedTableName + "keyString " + comparisonOperator + " ?  OR  " + qualifiedTableName + "keyString IS NULL)  AND  ";
     363    case IDBKey::DateType:
     364        return "(" + qualifiedTableName + "keyDate " + comparisonOperator + " ? OR " + qualifiedTableName + "keyDate IS NULL)  AND  " + qualifiedTableName + "keyString IS NULL  AND  ";
     365    case IDBKey::NumberType:
     366        return "(" + qualifiedTableName + "keyNumber " + comparisonOperator + " ? OR " + qualifiedTableName + "keyNumber IS NULL)  AND  " + qualifiedTableName + "keyString IS NULL  AND  " + qualifiedTableName + "keyDate IS NULL  AND  ";
     367    case IDBKey::NullType:
     368        if (comparisonOperator == "<")
     369            return "0 != 0  AND  ";
     370        return qualifiedTableName + "keyString IS NULL  AND  " + qualifiedTableName + "keyDate IS NULL  AND  " + qualifiedTableName + "keyNumber IS NULL  AND  ";
     371    }
     372    ASSERT_NOT_REACHED();
     373    return "";
    337374}
    338375
     
    416453}
    417454
     455void IDBBackingStore::deleteObjectStoreRecord(int64_t, int64_t objectStoreDataId)
     456{
     457    SQLiteStatement osQuery(m_db, "DELETE FROM ObjectStoreData WHERE id = ?");
     458    bool ok = osQuery.prepare() == SQLResultOk;
     459    ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
     460
     461    osQuery.bindInt64(1, objectStoreDataId);
     462
     463    ok = osQuery.step() == SQLResultDone;
     464    ASSERT_UNUSED(ok, ok);
     465
     466    SQLiteStatement indexQuery(m_db, "DELETE FROM IndexData WHERE objectStoreDataId = ?");
     467    ok = indexQuery.prepare() == SQLResultOk;
     468    ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
     469
     470    indexQuery.bindInt64(1, objectStoreDataId);
     471
     472    ok = indexQuery.step() == SQLResultDone;
     473    ASSERT_UNUSED(ok, ok);
     474}
     475
    418476double IDBBackingStore::nextAutoIncrementNumber(int64_t objectStoreId)
    419477{
     
    428486
    429487    return query.getColumnDouble(0);
     488}
     489
     490bool IDBBackingStore::keyExistsInObjectStore(int64_t objectStoreId, const IDBKey& key, int64_t& foundObjectStoreDataId)
     491{
     492    String sql = String("SELECT id FROM ObjectStoreData WHERE objectStoreId = ? AND ") + whereSyntaxForKey(key);
     493    SQLiteStatement query(m_db, sql);
     494    bool ok = query.prepare() == SQLResultOk;
     495    ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
     496
     497    query.bindInt64(1, objectStoreId);
     498    bindKeyToQuery(query, 2, key);
     499
     500    if (query.step() != SQLResultRow)
     501        return false;
     502
     503    foundObjectStoreDataId = query.getColumnInt64(0);
     504    return true;
    430505}
    431506
     
    516591}
    517592
     593String IDBBackingStore::getObjectViaIndex(int64_t indexId, const IDBKey& key)
     594{
     595    String sql = String("SELECT ")
     596                 + "ObjectStoreData.value "
     597                 + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id "
     598                 + "WHERE IndexData.indexId = ?  AND  " + whereSyntaxForKey(key, "IndexData.")
     599                 + "ORDER BY IndexData.id LIMIT 1"; // Order by insertion order when all else fails.
     600    SQLiteStatement query(m_db, sql);
     601    bool ok = query.prepare() == SQLResultOk;
     602    ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
     603
     604    query.bindInt64(1, indexId);
     605    bindKeyToQuery(query, 2, key);
     606
     607    if (query.step() != SQLResultRow)
     608        return String();
     609
     610    String foundValue = query.getColumnBlobAsString(0);
     611    ASSERT(query.step() != SQLResultRow);
     612    return foundValue;
     613}
     614
     615static PassRefPtr<IDBKey> keyFromQuery(SQLiteStatement& query, int baseColumn)
     616{
     617    if (query.columnCount() <= baseColumn)
     618        return 0;
     619
     620    if (!query.isColumnNull(baseColumn))
     621        return IDBKey::createString(query.getColumnText(baseColumn));
     622
     623    if (!query.isColumnNull(baseColumn + 1))
     624        return IDBKey::createDate(query.getColumnDouble(baseColumn + 1));
     625
     626    if (!query.isColumnNull(baseColumn + 2))
     627        return IDBKey::createNumber(query.getColumnDouble(baseColumn + 2));
     628
     629    return IDBKey::createNull();
     630}
     631
     632PassRefPtr<IDBKey> IDBBackingStore::getPrimaryKeyViaIndex(int64_t indexId, const IDBKey& key)
     633{
     634    String sql = String("SELECT ")
     635                 + "ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber "
     636                 + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id "
     637                 + "WHERE IndexData.indexId = ?  AND  " + whereSyntaxForKey(key, "IndexData.")
     638                 + "ORDER BY IndexData.id LIMIT 1"; // Order by insertion order when all else fails.
     639    SQLiteStatement query(m_db, sql);
     640    bool ok = query.prepare() == SQLResultOk;
     641    ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
     642
     643    query.bindInt64(1, indexId);
     644    bindKeyToQuery(query, 2, key);
     645
     646    if (query.step() != SQLResultRow)
     647        return false;
     648
     649    RefPtr<IDBKey> foundKey = keyFromQuery(query, 0);
     650    ASSERT(query.step() != SQLResultRow);
     651    return foundKey.release();
     652}
     653
     654bool IDBBackingStore::keyExistsInIndex(int64_t indexId, const IDBKey& key)
     655{
     656    String sql = String("SELECT id FROM IndexData WHERE indexId = ? AND ") + whereSyntaxForKey(key);
     657    SQLiteStatement query(m_db, sql);
     658    bool ok = query.prepare() == SQLResultOk;
     659    ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
     660
     661    query.bindInt64(1, indexId);
     662    bindKeyToQuery(query, 2, key);
     663
     664    return query.step() == SQLResultRow;
     665}
     666
     667namespace {
     668
     669class CursorImplCommon : public IDBBackingStore::Cursor {
     670public:
     671    CursorImplCommon(SQLiteDatabase& sqliteDatabase, String query, bool uniquenessConstraint)
     672        : m_query(sqliteDatabase, query)
     673        , m_db(sqliteDatabase)
     674        , m_uniquenessConstraint(uniquenessConstraint)
     675    {
     676    }
     677    virtual ~CursorImplCommon() {}
     678
     679    // IDBBackingStore::Cursor
     680    virtual bool continueFunction(const IDBKey*);
     681    virtual PassRefPtr<IDBKey> key() { return m_currentKey; }
     682    virtual PassRefPtr<IDBKey> primaryKey() { return m_currentKey; }
     683    virtual String value() = 0;
     684    virtual int64_t objectStoreDataId() = 0;
     685    virtual int64_t indexDataId() = 0;
     686
     687    virtual void loadCurrentRow() = 0;
     688    virtual bool currentRowExists() = 0;
     689
     690    SQLiteStatement m_query;
     691
     692protected:
     693    SQLiteDatabase& m_db;
     694    bool m_uniquenessConstraint;
     695    int64_t m_currentId;
     696    RefPtr<IDBKey> m_currentKey;
     697};
     698
     699bool CursorImplCommon::continueFunction(const IDBKey* key)
     700{
     701    while (true) {
     702        if (m_query.step() != SQLResultRow)
     703            return false;
     704
     705        RefPtr<IDBKey> oldKey = m_currentKey;
     706        loadCurrentRow();
     707
     708        // Skip if this entry has been deleted from the object store.
     709        if (!currentRowExists())
     710            continue;
     711
     712        // If a key was supplied, we must loop until we find that key (or hit the end).
     713        if (key && !key->isEqual(m_currentKey.get()))
     714            continue;
     715
     716        // If we don't have a uniqueness constraint, we can stop now.
     717        if (!m_uniquenessConstraint)
     718            break;
     719        if (!m_currentKey->isEqual(oldKey.get()))
     720            break;
     721    }
     722
     723    return true;
     724}
     725
     726class ObjectStoreCursorImpl : public CursorImplCommon {
     727public:
     728    ObjectStoreCursorImpl(SQLiteDatabase& sqliteDatabase, String query, bool uniquenessConstraint)
     729        : CursorImplCommon(sqliteDatabase, query, uniquenessConstraint)
     730    {
     731    }
     732
     733    // CursorImplCommon.
     734    virtual String value() { return m_currentValue; }
     735    virtual int64_t objectStoreDataId() { return m_currentId; }
     736    virtual int64_t indexDataId() { ASSERT_NOT_REACHED(); return 0; }
     737    virtual void loadCurrentRow();
     738    virtual bool currentRowExists();
     739
     740private:
     741    String m_currentValue;
     742};
     743
     744void ObjectStoreCursorImpl::loadCurrentRow()
     745{
     746    m_currentId = m_query.getColumnInt64(0);
     747    m_currentKey = keyFromQuery(m_query, 1);
     748    m_currentValue = m_query.getColumnBlobAsString(4);
     749}
     750
     751bool ObjectStoreCursorImpl::currentRowExists()
     752{
     753    String sql = "SELECT id FROM ObjectStoreData WHERE id = ?";
     754    SQLiteStatement statement(m_db, sql);
     755
     756    bool ok = statement.prepare() == SQLResultOk;
     757    ASSERT_UNUSED(ok, ok);
     758
     759    statement.bindInt64(1, m_currentId);
     760    return statement.step() == SQLResultRow;
     761}
     762
     763class IndexKeyCursorImpl : public CursorImplCommon {
     764public:
     765    IndexKeyCursorImpl(SQLiteDatabase& sqliteDatabase, String query, bool uniquenessConstraint)
     766        : CursorImplCommon(sqliteDatabase, query, uniquenessConstraint)
     767    {
     768    }
     769
     770    // CursorImplCommon
     771    virtual PassRefPtr<IDBKey> primaryKey() { return m_currentPrimaryKey; }
     772    virtual String value() { ASSERT_NOT_REACHED(); return String(); }
     773    virtual int64_t objectStoreDataId() { ASSERT_NOT_REACHED(); return 0; }
     774    virtual int64_t indexDataId() { return m_currentId; }
     775    virtual void loadCurrentRow();
     776    virtual bool currentRowExists();
     777
     778private:
     779    RefPtr<IDBKey> m_currentPrimaryKey;
     780};
     781
     782void IndexKeyCursorImpl::loadCurrentRow()
     783{
     784    m_currentId = m_query.getColumnInt64(0);
     785    m_currentKey = keyFromQuery(m_query, 1);
     786    m_currentPrimaryKey = keyFromQuery(m_query, 4);
     787}
     788
     789bool IndexKeyCursorImpl::currentRowExists()
     790{
     791    String sql = "SELECT id FROM IndexData WHERE id = ?";
     792    SQLiteStatement statement(m_db, sql);
     793
     794    bool ok = statement.prepare() == SQLResultOk;
     795    ASSERT_UNUSED(ok, ok);
     796
     797    statement.bindInt64(1, m_currentId);
     798    return statement.step() == SQLResultRow;
     799}
     800
     801class IndexCursorImpl : public CursorImplCommon {
     802public:
     803    IndexCursorImpl(SQLiteDatabase& sqliteDatabase, String query, bool uniquenessConstraint)
     804        : CursorImplCommon(sqliteDatabase, query, uniquenessConstraint)
     805    {
     806    }
     807
     808    // CursorImplCommon
     809    virtual PassRefPtr<IDBKey> primaryKey() { return m_currentPrimaryKey; }
     810    virtual String value() { return m_currentValue; }
     811    virtual int64_t objectStoreDataId() { ASSERT_NOT_REACHED(); return 0; }
     812    virtual int64_t indexDataId() { return m_currentId; }
     813    virtual void loadCurrentRow();
     814    virtual bool currentRowExists();
     815
     816private:
     817    RefPtr<IDBKey> m_currentPrimaryKey;
     818    String m_currentValue;
     819};
     820
     821void IndexCursorImpl::loadCurrentRow()
     822{
     823    m_currentId = m_query.getColumnInt64(0);
     824    m_currentKey = keyFromQuery(m_query, 1);
     825    m_currentValue = m_query.getColumnBlobAsString(4);
     826    m_currentPrimaryKey = keyFromQuery(m_query, 5);
     827}
     828
     829bool IndexCursorImpl::currentRowExists()
     830{
     831    String sql = "SELECT id FROM IndexData WHERE id = ?";
     832    SQLiteStatement statement(m_db, sql);
     833
     834    bool ok = statement.prepare() == SQLResultOk;
     835    ASSERT_UNUSED(ok, ok);
     836
     837    statement.bindInt64(1, m_currentId);
     838    return statement.step() == SQLResultRow;
     839}
     840
     841} // namespace
     842
     843PassRefPtr<IDBBackingStore::Cursor> IDBBackingStore::openObjectStoreCursor(int64_t objectStoreId, const IDBKeyRange* range, IDBCursor::Direction direction)
     844{
     845    bool lowerBound = range && range->lower();
     846    bool upperBound = range && range->upper();
     847
     848    String sql = "SELECT id, keyString, keyDate, keyNumber, value FROM ObjectStoreData WHERE ";
     849    if (lowerBound)
     850        sql += lowerCursorWhereFragment(*range->lower(), range->lowerOpen() ? "<" : "<=");
     851    if (upperBound)
     852        sql += upperCursorWhereFragment(*range->upper(), range->upperOpen() ? "<" : "<=");
     853    sql += "objectStoreId = ? ORDER BY ";
     854
     855    if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE)
     856        sql += "keyString, keyDate, keyNumber";
     857    else
     858        sql += "keyString DESC, keyDate DESC, keyNumber DESC";
     859
     860    RefPtr<ObjectStoreCursorImpl> cursor = adoptRef(new ObjectStoreCursorImpl(m_db, sql, direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::PREV_NO_DUPLICATE));
     861
     862    bool ok = cursor->m_query.prepare() == SQLResultOk;
     863    ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
     864
     865    int currentColumn = 1;
     866    if (lowerBound)
     867        currentColumn += bindKeyToQuery(cursor->m_query, currentColumn, *range->lower());
     868    if (upperBound)
     869        currentColumn += bindKeyToQuery(cursor->m_query, currentColumn, *range->upper());
     870    cursor->m_query.bindInt64(currentColumn, objectStoreId);
     871
     872    if (cursor->m_query.step() != SQLResultRow)
     873        return 0;
     874
     875    cursor->loadCurrentRow();
     876    return cursor.release();
     877}
     878
     879PassRefPtr<IDBBackingStore::Cursor> IDBBackingStore::openIndexKeyCursor(int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction)
     880{
     881    String sql = String("SELECT IndexData.id, IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, ")
     882                 + ("ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ")
     883                 + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id WHERE ";
     884
     885    bool lowerBound = range && range->lower();
     886    bool upperBound = range && range->upper();
     887
     888    if (lowerBound)
     889        sql += lowerCursorWhereFragment(*range->lower(), range->lowerOpen() ? "<" : "<=", "IndexData.");
     890    if (upperBound)
     891        sql += upperCursorWhereFragment(*range->upper(), range->upperOpen() ? "<" : "<=", "IndexData.");
     892    sql += "IndexData.indexId = ? ORDER BY ";
     893
     894    if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE)
     895        sql += "IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, IndexData.id";
     896    else
     897        sql += "IndexData.keyString DESC, IndexData.keyDate DESC, IndexData.keyNumber DESC, IndexData.id DESC";
     898
     899    RefPtr<IndexKeyCursorImpl> cursor = adoptRef(new IndexKeyCursorImpl(m_db, sql, direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::PREV_NO_DUPLICATE));
     900
     901    bool ok = cursor->m_query.prepare() == SQLResultOk;
     902    ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
     903
     904    int indexColumn = 1;
     905    if (lowerBound)
     906        indexColumn += bindKeyToQuery(cursor->m_query, indexColumn, *range->lower());
     907    if (upperBound)
     908        indexColumn += bindKeyToQuery(cursor->m_query, indexColumn, *range->upper());
     909    cursor->m_query.bindInt64(indexColumn, indexId);
     910
     911    if (cursor->m_query.step() != SQLResultRow)
     912        return 0;
     913
     914    cursor->loadCurrentRow();
     915    return cursor.release();
     916}
     917
     918PassRefPtr<IDBBackingStore::Cursor> IDBBackingStore::openIndexCursor(int64_t indexId, const IDBKeyRange* range, IDBCursor::Direction direction)
     919{
     920    String sql = String("SELECT IndexData.id, IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, ")
     921                 + ("ObjectStoreData.value, ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ")
     922                 + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id WHERE ";
     923
     924    bool lowerBound = range && range->lower();
     925    bool upperBound = range && range->upper();
     926
     927    if (lowerBound)
     928        sql += lowerCursorWhereFragment(*range->lower(), range->lowerOpen() ? "<" : "<=", "IndexData.");
     929    if (upperBound)
     930        sql += upperCursorWhereFragment(*range->upper(), range->upperOpen() ? "<" : "<=", "IndexData.");
     931    sql += "IndexData.indexId = ? ORDER BY ";
     932
     933    if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE)
     934        sql += "IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, IndexData.id";
     935    else
     936        sql += "IndexData.keyString DESC, IndexData.keyDate DESC, IndexData.keyNumber DESC, IndexData.id DESC";
     937
     938    RefPtr<IndexCursorImpl> cursor = adoptRef(new IndexCursorImpl(m_db, sql, direction == IDBCursor::NEXT_NO_DUPLICATE || direction == IDBCursor::PREV_NO_DUPLICATE));
     939
     940    bool ok = cursor->m_query.prepare() == SQLResultOk;
     941    ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
     942
     943    int indexColumn = 1;
     944    if (lowerBound)
     945        indexColumn += bindKeyToQuery(cursor->m_query, indexColumn, *range->lower());
     946    if (upperBound)
     947        indexColumn += bindKeyToQuery(cursor->m_query, indexColumn, *range->upper());
     948    cursor->m_query.bindInt64(indexColumn, indexId);
     949
     950    if (cursor->m_query.step() != SQLResultRow)
     951        return 0;
     952
     953    cursor->loadCurrentRow();
     954    return cursor.release();
     955}
     956
    518957} // namespace WebCore
    519958
  • trunk/Source/WebCore/storage/IDBBackingStore.h

    r79445 r80220  
    2929#if ENABLE(INDEXED_DATABASE)
    3030
     31#include "IDBCursor.h"
    3132#include "SQLiteDatabase.h"
    3233#include <wtf/PassRefPtr.h>
     
    3940class IDBFactoryBackendImpl;
    4041class IDBKey;
     42class IDBKeyRange;
    4143class SecurityOrigin;
    4244
     
    5557    bool putObjectStoreRecord(int64_t objectStoreId, const IDBKey&, const String& value, int64_t& rowId, bool invalidRowId);
    5658    void clearObjectStore(int64_t objectStoreId);
     59    void deleteObjectStoreRecord(int64_t objectStoreId, int64_t objectStoreDataId);
    5760    double nextAutoIncrementNumber(int64_t objectStoreId);
     61    bool keyExistsInObjectStore(int64_t objectStoreId, const IDBKey&, int64_t& foundObjectStoreDataId);
    5862
    5963    class ObjectStoreRecordCallback {
     
    6973    bool putIndexDataForRecord(int64_t indexId, const IDBKey&, int64_t objectStoreDataId);
    7074    bool deleteIndexDataForRecord(int64_t objectStoreDataId);
     75    String getObjectViaIndex(int64_t indexId, const IDBKey&);
     76    PassRefPtr<IDBKey> getPrimaryKeyViaIndex(int64_t indexId, const IDBKey&);
     77    bool keyExistsInIndex(int64_t indexId, const IDBKey&);
     78
     79    class Cursor : public RefCounted<Cursor> {
     80    public:
     81        virtual bool continueFunction(const IDBKey* = 0) = 0;
     82        virtual PassRefPtr<IDBKey> key() = 0;
     83        virtual PassRefPtr<IDBKey> primaryKey() = 0;
     84        virtual String value() = 0;
     85        virtual int64_t objectStoreDataId() = 0;
     86        virtual int64_t indexDataId() = 0;
     87        virtual ~Cursor() {};
     88    };
     89
     90    PassRefPtr<Cursor> openObjectStoreCursor(int64_t objectStoreId, const IDBKeyRange*, IDBCursor::Direction);
     91    PassRefPtr<Cursor> openIndexKeyCursor(int64_t indexId, const IDBKeyRange*, IDBCursor::Direction);
     92    PassRefPtr<Cursor> openIndexCursor(int64_t indexId, const IDBKeyRange*, IDBCursor::Direction);
    7193
    7294    SQLiteDatabase& db() { return m_db; }
  • trunk/Source/WebCore/storage/IDBCursorBackendImpl.cpp

    r80171 r80220  
    3232#include "IDBBackingStore.h"
    3333#include "IDBCallbacks.h"
    34 #include "IDBDatabaseBackendImpl.h"
    3534#include "IDBDatabaseError.h"
    3635#include "IDBDatabaseException.h"
    37 #include "IDBIndexBackendImpl.h"
    3836#include "IDBKeyRange.h"
    3937#include "IDBObjectStoreBackendImpl.h"
    4038#include "IDBRequest.h"
    4139#include "IDBTransactionBackendInterface.h"
    42 #include "SQLiteDatabase.h"
    43 #include "SQLiteStatement.h"
    4440#include "SerializedScriptValue.h"
    4541
    4642namespace WebCore {
    4743
    48 IDBCursorBackendImpl::IDBCursorBackendImpl(IDBBackingStore* backingStore, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, CursorType cursorType, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore)
    49     : m_backingStore(backingStore)
    50     , m_keyRange(keyRange)
     44IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBBackingStore::Cursor> cursor, IDBCursor::Direction direction, CursorType cursorType, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore)
     45    : m_cursor(cursor)
    5146    , m_direction(direction)
    52     , m_query(query)
    5347    , m_cursorType(cursorType)
    5448    , m_transaction(transaction)
    5549    , m_objectStore(objectStore)
    5650{
    57     loadCurrentRow();
    5851}
    5952
     
    6962PassRefPtr<IDBKey> IDBCursorBackendImpl::key() const
    7063{
    71     return m_currentKey;
     64    return m_cursor->key();
    7265}
    7366
    7467PassRefPtr<IDBKey> IDBCursorBackendImpl::primaryKey() const
    7568{
    76     return m_currentPrimaryKey;
     69    return m_cursor->primaryKey();
    7770}
    7871
     
    8073{
    8174    ASSERT(m_cursorType != IndexKeyCursor);
    82     return m_currentValue;
     75    return SerializedScriptValue::createFromWire(m_cursor->value());
    8376}
    8477
    8578void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBCallbacks> callbacks, ExceptionCode& ec)
    8679{
    87     if (!m_query || m_currentId == InvalidId || m_cursorType == IndexKeyCursor) {
     80    if (!m_cursor || m_cursorType == IndexKeyCursor) {
    8881        ec = IDBDatabaseException::NOT_ALLOWED_ERR;
    8982        return;
    9083    }
    9184
    92     m_objectStore->put(value, m_currentPrimaryKey, IDBObjectStoreBackendInterface::CursorUpdate, callbacks, m_transaction.get(), ec);
     85    m_objectStore->put(value, m_cursor->primaryKey(), IDBObjectStoreBackendInterface::CursorUpdate, callbacks, m_transaction.get(), ec);
    9386}
    9487
     
    10295}
    10396
    104 bool IDBCursorBackendImpl::currentRowExists()
    105 {
    106     String sql = m_cursorType == ObjectStoreCursor ? "SELECT id FROM ObjectStoreData WHERE id = ?" : "SELECT id FROM IndexData WHERE id = ?";
    107     SQLiteStatement statement(m_backingStore->db(), sql);
    108 
    109     bool ok = statement.prepare() == SQLResultOk;
    110     ASSERT_UNUSED(ok, ok);
    111 
    112     statement.bindInt64(1, m_currentId);
    113     return statement.step() == SQLResultRow;
    114 }
    115 
    11697// IMPORTANT: If this ever 1) fires an 'error' event and 2) it's possible to fire another event afterwards,
    11798//            IDBRequest::hasPendingActivity() will need to be modified to handle this!!!
     
    120101    RefPtr<IDBCursorBackendImpl> cursor = prpCursor;
    121102    RefPtr<IDBKey> key = prpKey;
    122     while (true) {
    123         if (!cursor->m_query || cursor->m_query->step() != SQLResultRow) {
    124             cursor->m_query = 0;
    125             cursor->m_currentId = InvalidId;
    126             cursor->m_currentKey = 0;
    127             cursor->m_currentPrimaryKey = 0;
    128             cursor->m_currentValue = 0;
    129             callbacks->onSuccess(SerializedScriptValue::nullValue());
    130             return;
    131         }
    132103
    133         RefPtr<IDBKey> oldKey = cursor->m_currentKey;
    134         cursor->loadCurrentRow();
    135 
    136         // Skip if this entry has been deleted from the object store.
    137         if (!cursor->currentRowExists())
    138             continue;
    139 
    140         // If a key was supplied, we must loop until we find that key (or hit the end).
    141         if (key && !key->isEqual(cursor->m_currentKey.get()))
    142             continue;
    143 
    144         // If we don't have a uniqueness constraint, we can stop now.
    145         if (cursor->m_direction == IDBCursor::NEXT || cursor->m_direction == IDBCursor::PREV)
    146             break;
    147         if (!cursor->m_currentKey->isEqual(oldKey.get()))
    148             break;
     104    if (!cursor->m_cursor || !cursor->m_cursor->continueFunction(key.get())) {
     105        cursor->m_cursor = 0;
     106        callbacks->onSuccess(SerializedScriptValue::nullValue());
     107        return;
    149108    }
    150109
     
    154113void IDBCursorBackendImpl::deleteFunction(PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
    155114{
    156     if (!m_query || m_currentId == InvalidId || m_cursorType == IndexKeyCursor) {
     115    if (!m_cursor || m_cursorType == IndexKeyCursor) {
    157116        ec = IDBDatabaseException::NOT_ALLOWED_ERR;
    158117        return;
    159118    }
    160119
    161     m_objectStore->deleteFunction(m_currentPrimaryKey, prpCallbacks, m_transaction.get(), ec);
    162 }
    163 
    164 
    165 void IDBCursorBackendImpl::loadCurrentRow()
    166 {
    167     // The column numbers depend on the query in IDBObjectStoreBackendImpl::openCursorInternal and/or IDBIndexBackendImpl::openCursorInternal.
    168     m_currentId = m_query->getColumnInt64(0);
    169     m_currentKey = IDBKey::fromQuery(*m_query, 1);
    170     m_currentValue = SerializedScriptValue::createFromWire(m_query->getColumnBlobAsString(4));
    171     m_currentPrimaryKey = IDBKey::fromQuery(*m_query, 5);
    172 }
    173 
    174 SQLiteDatabase& IDBCursorBackendImpl::database() const
    175 {
    176     return m_backingStore->db();
     120    m_objectStore->deleteFunction(m_cursor->primaryKey(), prpCallbacks, m_transaction.get(), ec);
    177121}
    178122
  • trunk/Source/WebCore/storage/IDBCursorBackendImpl.h

    r80171 r80220  
    3030#if ENABLE(INDEXED_DATABASE)
    3131
     32#include "IDBBackingStore.h"
    3233#include "IDBCursor.h"
    3334#include "IDBCursorBackendInterface.h"
     
    5051class IDBCursorBackendImpl : public IDBCursorBackendInterface {
    5152public:
    52     static PassRefPtr<IDBCursorBackendImpl> create(IDBBackingStore* backingStore, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, CursorType cursorType, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore)
     53    static PassRefPtr<IDBCursorBackendImpl> create(PassRefPtr<IDBBackingStore::Cursor> cursor, IDBCursor::Direction direction, CursorType cursorType, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore)
    5354    {
    54         return adoptRef(new IDBCursorBackendImpl(backingStore, keyRange, direction, query, cursorType, transaction, objectStore));
     55        return adoptRef(new IDBCursorBackendImpl(cursor, direction, cursorType, transaction, objectStore));
    5556    }
    5657    virtual ~IDBCursorBackendImpl();
     
    6566
    6667private:
    67     IDBCursorBackendImpl(IDBBackingStore*, PassRefPtr<IDBKeyRange>, IDBCursor::Direction, PassOwnPtr<SQLiteStatement> query, CursorType, IDBTransactionBackendInterface*, IDBObjectStoreBackendInterface*);
    68 
    69     bool currentRowExists();
    70     void loadCurrentRow();
    71     SQLiteDatabase& database() const;
     68    IDBCursorBackendImpl(PassRefPtr<IDBBackingStore::Cursor>, IDBCursor::Direction, CursorType, IDBTransactionBackendInterface*, IDBObjectStoreBackendInterface*);
    7269
    7370    static void continueFunctionInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl>, PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>);
    7471
    75     static const int64_t InvalidId = -1;
    76 
    77     RefPtr<IDBBackingStore> m_backingStore;
    78 
    79     RefPtr<IDBKeyRange> m_keyRange;
     72    RefPtr<IDBBackingStore::Cursor> m_cursor;
    8073    IDBCursor::Direction m_direction;
    81     OwnPtr<SQLiteStatement> m_query;
    8274    CursorType m_cursorType;
    83     int64_t m_currentId;
    84 
    85     RefPtr<IDBKey> m_currentKey;
    86     RefPtr<IDBKey> m_currentPrimaryKey;
    87     RefPtr<SerializedScriptValue> m_currentValue;
    88 
    8975    RefPtr<IDBTransactionBackendInterface> m_transaction;
    9076    RefPtr<IDBObjectStoreBackendInterface> m_objectStore;
  • trunk/Source/WebCore/storage/IDBIndexBackendImpl.cpp

    r80171 r80220  
    3838#include "IDBKeyRange.h"
    3939#include "IDBObjectStoreBackendImpl.h"
    40 #include "SQLiteDatabase.h"
    41 #include "SQLiteStatement.h"
    4240
    4341namespace WebCore {
     
    6967void IDBIndexBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> range, unsigned short untypedDirection, IDBCursorBackendInterface::CursorType cursorType, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
    7068{
    71     // Several files depend on this order of selects.
    72     String sql = String("SELECT IndexData.id, IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, ")
    73                  + ("ObjectStoreData.value, ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ")
    74                  + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id WHERE ";
     69    IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(untypedDirection);
    7570
    76     bool lowerBound = range && range->lower();
    77     bool upperBound = range && range->upper();
    78    
    79     if (lowerBound)
    80         sql += range->lower()->lowerCursorWhereFragment(range->lowerWhereClauseComparisonOperator(), "IndexData.");
    81     if (upperBound)
    82         sql += range->upper()->upperCursorWhereFragment(range->upperWhereClauseComparisonOperator(), "IndexData.");
    83     sql += "IndexData.indexId = ? ORDER BY ";
     71    RefPtr<IDBBackingStore::Cursor> backingStoreCursor;
    8472
    85     IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(untypedDirection);
    86     if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE)
    87         sql += "IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, IndexData.id";
    88     else
    89         sql += "IndexData.keyString DESC, IndexData.keyDate DESC, IndexData.keyNumber DESC, IndexData.id DESC";
     73    switch (cursorType) {
     74    case IDBCursorBackendInterface::IndexKeyCursor:
     75        backingStoreCursor = index->m_backingStore->openIndexKeyCursor(index->id(), range.get(), direction);
     76        break;
     77    case IDBCursorBackendInterface::IndexCursor:
     78        backingStoreCursor = index->m_backingStore->openIndexCursor(index->id(), range.get(), direction);
     79        break;
     80    case IDBCursorBackendInterface::ObjectStoreCursor:
     81    case IDBCursorBackendInterface::InvalidCursorType:
     82        ASSERT_NOT_REACHED();
     83        break;
     84    }
    9085
    91     OwnPtr<SQLiteStatement> query = adoptPtr(new SQLiteStatement(index->sqliteDatabase(), sql));
    92     bool ok = query->prepare() == SQLResultOk;
    93     ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
    94 
    95     int indexColumn = 1;
    96     if (lowerBound)
    97         indexColumn += range->lower()->bind(*query, indexColumn);
    98     if (upperBound)
    99         indexColumn += range->upper()->bind(*query, indexColumn);
    100     query->bindInt64(indexColumn, index->id());
    101 
    102     if (query->step() != SQLResultRow) {
     86    if (!backingStoreCursor) {
    10387        callbacks->onSuccess(SerializedScriptValue::nullValue());
    10488        return;
     
    10993    ASSERT(objectStore && !ec);
    11094
    111     RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(index->m_backingStore.get(), range, direction, query.release(), cursorType, transaction.get(), objectStore.get());
     95    RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.get(), direction, cursorType, transaction.get(), objectStore.get());
    11296    callbacks->onSuccess(cursor.release());
    11397}
     
    135119void IDBIndexBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKey> key, bool getObject, PassRefPtr<IDBCallbacks> callbacks)
    136120{
    137     String sql = String("SELECT ")
    138                  + (getObject ? "ObjectStoreData.value " : "ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ")
    139                  + "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id "
    140                  + "WHERE IndexData.indexId = ?  AND  " + key->whereSyntax("IndexData.")
    141                  + "ORDER BY IndexData.id LIMIT 1"; // Order by insertion order when all else fails.
    142     SQLiteStatement query(index->sqliteDatabase(), sql);
    143     bool ok = query.prepare() == SQLResultOk;
    144     ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
    145 
    146     query.bindInt64(1, index->id());
    147     key->bind(query, 2);
    148     if (query.step() != SQLResultRow) {
    149         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index."));
    150         return;
     121    // FIXME: Split getInternal into two functions, getting rid off |getObject|.
     122    if (getObject) {
     123        String value = index->m_backingStore->getObjectViaIndex(index->id(), *key);
     124        if (value.isNull()) {
     125            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index."));
     126            return;
     127        }
     128        callbacks->onSuccess(SerializedScriptValue::createFromWire(value));
     129    } else {
     130        RefPtr<IDBKey> keyResult = index->m_backingStore->getPrimaryKeyViaIndex(index->id(), *key);
     131        if (!keyResult) {
     132            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index."));
     133            return;
     134        }
     135        callbacks->onSuccess(keyResult.get());
    151136    }
    152 
    153     if (getObject)
    154         callbacks->onSuccess(SerializedScriptValue::createFromWire(query.getColumnText(0)));
    155     else
    156         callbacks->onSuccess(IDBKey::fromQuery(query, 0));
    157     ASSERT(query.step() != SQLResultRow);
    158137}
    159138
     
    176155}
    177156
    178 static String whereClause(IDBKey* key)
    179 {
    180     return "WHERE indexId = ?  AND  " + key->whereSyntax();
    181 }
    182 
    183 static void bindWhereClause(SQLiteStatement& query, int64_t id, IDBKey* key)
    184 {
    185     query.bindInt64(1, id);
    186     key->bind(query, 2);
    187 }
    188 
    189157bool IDBIndexBackendImpl::addingKeyAllowed(IDBKey* key)
    190158{
     
    192160        return true;
    193161
    194     SQLiteStatement query(sqliteDatabase(), "SELECT id FROM IndexData " + whereClause(key));
    195     bool ok = query.prepare() == SQLResultOk;
    196     ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
    197     bindWhereClause(query, m_id, key);
    198     bool existingValue = query.step() == SQLResultRow;
    199 
    200     return !existingValue;
    201 }
    202 
    203 SQLiteDatabase& IDBIndexBackendImpl::sqliteDatabase() const
    204 {
    205     return m_backingStore->db();
     162    return !m_backingStore->keyExistsInIndex(m_id, *key);
    206163}
    207164
  • trunk/Source/WebCore/storage/IDBIndexBackendImpl.h

    r80171 r80220  
    7777    IDBIndexBackendImpl(IDBBackingStore*, const String& name, const String& storeName, const String& keyPath, bool unique);
    7878
    79     SQLiteDatabase& sqliteDatabase() const;
    80 
    8179    static void openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBKeyRange>, unsigned short direction, IDBCursorBackendInterface::CursorType, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBTransactionBackendInterface>);
    8280    static void getInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBKey>, bool getObject, PassRefPtr<IDBCallbacks>);
  • trunk/Source/WebCore/storage/IDBKey.cpp

    r74342 r80220  
    2929#if ENABLE(INDEXED_DATABASE)
    3030
    31 #include "SQLiteStatement.h"
    32 #include "SerializedScriptValue.h"
    33 
    3431namespace WebCore {
    3532
     
    4340}
    4441
    45 PassRefPtr<IDBKey> IDBKey::fromQuery(SQLiteStatement& query, int baseColumn)
    46 {
    47     if (query.columnCount() <= baseColumn)
    48         return 0;
    49 
    50     if (!query.isColumnNull(baseColumn))
    51         return IDBKey::createString(query.getColumnText(baseColumn));
    52 
    53     if (!query.isColumnNull(baseColumn + 1))
    54         return IDBKey::createDate(query.getColumnDouble(baseColumn + 1));
    55 
    56     if (!query.isColumnNull(baseColumn + 2))
    57         return IDBKey::createNumber(query.getColumnDouble(baseColumn + 2));
    58 
    59     return IDBKey::createNull();
    60 }
    61 
    62 bool IDBKey::isEqual(IDBKey* other)
     42bool IDBKey::isEqual(IDBKey* other) const
    6343{
    6444    if (!other || other->m_type != m_type)
     
    8060}
    8161
    82 String IDBKey::whereSyntax(String qualifiedTableName) const
    83 {
    84     switch (m_type) {
    85     case IDBKey::StringType:
    86         return qualifiedTableName + "keyString = ?  AND  " + qualifiedTableName + "keyDate IS NULL  AND  " + qualifiedTableName + "keyNumber IS NULL  ";
    87     case IDBKey::NumberType:
    88         return qualifiedTableName + "keyString IS NULL  AND  " + qualifiedTableName + "keyDate IS NULL  AND  " + qualifiedTableName + "keyNumber = ?  ";
    89     case IDBKey::DateType:
    90         return qualifiedTableName + "keyString IS NULL  AND  " + qualifiedTableName + "keyDate = ?  AND  " + qualifiedTableName + "keyNumber IS NULL  ";
    91     case IDBKey::NullType:
    92         return qualifiedTableName + "keyString IS NULL  AND  " + qualifiedTableName + "keyDate IS NULL  AND  " + qualifiedTableName + "keyNumber IS NULL  ";
    93     }
    94 
    95     ASSERT_NOT_REACHED();
    96     return "";
    97 }
    98 
    99 String IDBKey::lowerCursorWhereFragment(String comparisonOperator, String qualifiedTableName)
    100 {
    101     switch (m_type) {
    102     case StringType:
    103         return "? " + comparisonOperator + " " + qualifiedTableName + "keyString  AND  ";
    104     case DateType:
    105         return "(? " + comparisonOperator + " " + qualifiedTableName + "keyDate  OR NOT " + qualifiedTableName + "keyString IS NULL)  AND  ";
    106     case NumberType:
    107         return "(? " + comparisonOperator + " " + qualifiedTableName + "keyNumber  OR  NOT " + qualifiedTableName + "keyString IS NULL  OR  NOT " + qualifiedTableName + "keyDate IS NULL)  AND  ";
    108     case NullType:
    109         if (comparisonOperator == "<")
    110             return "NOT(" + qualifiedTableName + "keyString IS NULL  AND  " + qualifiedTableName + "keyDate IS NULL  AND  " + qualifiedTableName + "keyNumber IS NULL)  AND  ";
    111         return ""; // If it's =, the upper bound half will do the constraining. If it's <=, then that's a no-op.
    112     }
    113     ASSERT_NOT_REACHED();
    114     return "";
    115 }
    116 
    117 String IDBKey::upperCursorWhereFragment(String comparisonOperator, String qualifiedTableName)
    118 {
    119     switch (m_type) {
    120     case StringType:
    121         return "(" + qualifiedTableName + "keyString " + comparisonOperator + " ?  OR  " + qualifiedTableName + "keyString IS NULL)  AND  ";
    122     case DateType:
    123         return "(" + qualifiedTableName + "keyDate " + comparisonOperator + " ? OR " + qualifiedTableName + "keyDate IS NULL)  AND  " + qualifiedTableName + "keyString IS NULL  AND  ";
    124     case NumberType:
    125         return "(" + qualifiedTableName + "keyNumber " + comparisonOperator + " ? OR " + qualifiedTableName + "keyNumber IS NULL)  AND  " + qualifiedTableName + "keyString IS NULL  AND  " + qualifiedTableName + "keyDate IS NULL  AND  ";
    126     case NullType:
    127         if (comparisonOperator == "<")
    128             return "0 != 0  AND  ";
    129         return qualifiedTableName + "keyString IS NULL  AND  " + qualifiedTableName + "keyDate IS NULL  AND  " + qualifiedTableName + "keyNumber IS NULL  AND  ";
    130     }
    131     ASSERT_NOT_REACHED();
    132     return "";
    133 }
    134 
    135 // Returns the number of items bound.
    136 int IDBKey::bind(SQLiteStatement& query, int column) const
    137 {
    138     switch (m_type) {
    139     case IDBKey::StringType:
    140         query.bindText(column, m_string);
    141         return 1;
    142     case IDBKey::DateType:
    143         query.bindDouble(column, m_date);
    144         return 1;
    145     case IDBKey::NumberType:
    146         query.bindDouble(column, m_number);
    147         return 1;
    148     case IDBKey::NullType:
    149         return 0;
    150     }
    151 
    152     ASSERT_NOT_REACHED();
    153     return 0;
    154 }
    155 
    156 void IDBKey::bindWithNulls(SQLiteStatement& query, int baseColumn) const
    157 {
    158     switch (m_type) {
    159     case IDBKey::StringType:
    160         query.bindText(baseColumn + 0, m_string);
    161         query.bindNull(baseColumn + 1);
    162         query.bindNull(baseColumn + 2);
    163         break;
    164     case IDBKey::DateType:
    165         query.bindNull(baseColumn + 0);
    166         query.bindDouble(baseColumn + 1, m_date);
    167         query.bindNull(baseColumn + 2);
    168         break;
    169     case IDBKey::NumberType:
    170         query.bindNull(baseColumn + 0);
    171         query.bindNull(baseColumn + 1);
    172         query.bindDouble(baseColumn + 2, m_number);
    173         break;
    174     case IDBKey::NullType:
    175         query.bindNull(baseColumn + 0);
    176         query.bindNull(baseColumn + 1);
    177         query.bindNull(baseColumn + 2);
    178         break;
    179     default:
    180         ASSERT_NOT_REACHED();
    181     }
    182 }
    183 
    18462} // namespace WebCore
    18563
  • trunk/Source/WebCore/storage/IDBKey.h

    r74266 r80220  
    100100    }
    101101
    102     static PassRefPtr<IDBKey> fromQuery(SQLiteStatement& query, int baseColumn);
    103 
    104     bool isEqual(IDBKey* other);
    105     String whereSyntax(String qualifiedTableName = "") const;
    106     String lowerCursorWhereFragment(String comparisonOperator, String qualifiedTableName = "");
    107     String upperCursorWhereFragment(String comparisonOperator, String qualifiedTableName = "");
    108     int bind(SQLiteStatement& query, int column) const;
    109     void bindWithNulls(SQLiteStatement& query, int baseColumn) const;
     102    bool isEqual(IDBKey* other) const;
    110103
    111104    using ThreadSafeShared<IDBKey>::ref;
  • trunk/Source/WebCore/storage/IDBKeyRange.cpp

    r80076 r80220  
    6262}
    6363
    64 String IDBKeyRange::lowerWhereClauseComparisonOperator() const
    65 {
    66     ASSERT(m_lower);
    67     if (m_lowerOpen)
    68         return "<";
    69     return "<=";
    70 }
    71 
    72 String IDBKeyRange::upperWhereClauseComparisonOperator() const
    73 {
    74     ASSERT(m_upper);
    75     if (m_upperOpen)
    76         return "<";
    77     return "<=";
    78 }
    79 
    8064} // namespace WebCore
    8165
  • trunk/Source/WebCore/storage/IDBKeyRange.h

    r80076 r80220  
    4444    ~IDBKeyRange() { }
    4545
    46 
    4746    PassRefPtr<IDBKey> lower() const { return m_lower; }
    4847    PassRefPtr<IDBKey> upper() const { return m_upper; }
    4948    bool lowerOpen() const { return m_lowerOpen; }
    5049    bool upperOpen() const { return m_upperOpen; }
    51 
    52     String lowerWhereClauseComparisonOperator() const;
    53     String upperWhereClauseComparisonOperator() const;
    5450
    5551    static PassRefPtr<IDBKeyRange> only(PassRefPtr<IDBKey> value);
  • trunk/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp

    r80171 r80220  
    4444#include "IDBTransactionBackendInterface.h"
    4545#include "ScriptExecutionContext.h"
    46 #include "SQLiteDatabase.h"
    47 #include "SQLiteStatement.h"
    48 #include "SQLiteTransaction.h"
    4946
    5047namespace WebCore {
     
    8380}
    8481
    85 static String whereClause(IDBKey* key)
    86 {
    87     return "WHERE objectStoreId = ?  AND  " + key->whereSyntax();
    88 }
    89 
    90 static void bindWhereClause(SQLiteStatement& query, int64_t id, IDBKey* key)
    91 {
    92     query.bindInt64(1, id);
    93     key->bind(query, 2);
    94 }
    95 
    9682void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
    9783{
     
    242228    }
    243229
    244     SQLiteStatement getQuery(objectStore->sqliteDatabase(), "SELECT id FROM ObjectStoreData " + whereClause(key.get()));
    245     bool ok = getQuery.prepare() == SQLResultOk;
    246     ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
    247 
    248     bindWhereClause(getQuery, objectStore->id(), key.get());
    249     bool isExistingValue = getQuery.step() == SQLResultRow;
     230    int64_t dataRowId = InvalidId;
     231    bool isExistingValue = objectStore->m_backingStore->keyExistsInObjectStore(objectStore->id(), *key, dataRowId);
     232
    250233    if (putMode == AddOnly && isExistingValue) {
    251234        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
     
    255238    // Before this point, don't do any mutation.  After this point, rollback the transaction in case of error.
    256239
    257     int64_t dataRowId = isExistingValue ? getQuery.getColumnInt(0) : InvalidId;
    258240    if (!objectStore->m_backingStore->putObjectStoreRecord(objectStore->id(), *key, value->toWireString(), dataRowId, dataRowId == InvalidId)) {
    259241        // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
     
    302284void IDBObjectStoreBackendImpl::deleteInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
    303285{
    304     SQLiteStatement idQuery(objectStore->sqliteDatabase(), "SELECT id FROM ObjectStoreData " + whereClause(key.get()));
    305     bool ok = idQuery.prepare() == SQLResultOk;
    306     ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
    307     bindWhereClause(idQuery, objectStore->id(), key.get());
    308     if (idQuery.step() != SQLResultRow) {
     286    int64_t id;
     287    if (!objectStore->m_backingStore->keyExistsInObjectStore(objectStore->id(), *key, id)) {
    309288        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the object store."));
    310289        return;
    311290    }
    312291
    313     int64_t id = idQuery.getColumnInt64(0);
    314 
    315     SQLiteStatement osQuery(objectStore->sqliteDatabase(), "DELETE FROM ObjectStoreData WHERE id = ?");
    316     ok = osQuery.prepare() == SQLResultOk;
    317     ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
    318 
    319     osQuery.bindInt64(1, id);
    320 
    321     ok = osQuery.step() == SQLResultDone;
    322     ASSERT_UNUSED(ok, ok);
    323 
    324     SQLiteStatement indexQuery(objectStore->sqliteDatabase(), "DELETE FROM IndexData WHERE objectStoreDataId = ?");
    325     ok = indexQuery.prepare() == SQLResultOk;
    326     ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
    327 
    328     indexQuery.bindInt64(1, id);
    329 
    330     ok = indexQuery.step() == SQLResultDone;
    331     ASSERT_UNUSED(ok, ok);
    332 
     292    objectStore->m_backingStore->deleteObjectStoreRecord(objectStore->id(), id);
    333293    callbacks->onSuccess(SerializedScriptValue::nullValue());
    334294}
     
    485445void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
    486446{
    487     bool lowerBound = range && range->lower();
    488     bool upperBound = range && range->upper();
    489 
    490     // Several files depend on this order of selects.
    491     String sql = "SELECT id, keyString, keyDate, keyNumber, value, keyString, keyDate, keyNumber FROM ObjectStoreData WHERE ";
    492     if (lowerBound)
    493         sql += range->lower()->lowerCursorWhereFragment(range->lowerWhereClauseComparisonOperator());
    494     if (upperBound)
    495         sql += range->upper()->upperCursorWhereFragment(range->upperWhereClauseComparisonOperator());
    496     sql += "objectStoreId = ? ORDER BY ";
    497 
    498447    IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(tmpDirection);
    499     if (direction == IDBCursor::NEXT || direction == IDBCursor::NEXT_NO_DUPLICATE)
    500         sql += "keyString, keyDate, keyNumber";
    501     else
    502         sql += "keyString DESC, keyDate DESC, keyNumber DESC";
    503 
    504     OwnPtr<SQLiteStatement> query = adoptPtr(new SQLiteStatement(objectStore->sqliteDatabase(), sql));
    505     bool ok = query->prepare() == SQLResultOk;
    506     ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
    507 
    508     int currentColumn = 1;
    509     if (lowerBound)
    510         currentColumn += range->lower()->bind(*query, currentColumn);
    511     if (upperBound)
    512         currentColumn += range->upper()->bind(*query, currentColumn);
    513     query->bindInt64(currentColumn, objectStore->id());
    514 
    515     if (query->step() != SQLResultRow) {
     448
     449    RefPtr<IDBBackingStore::Cursor> backingStoreCursor = objectStore->m_backingStore->openObjectStoreCursor(objectStore->id(), range.get(), direction);
     450    if (!backingStoreCursor) {
    516451        callbacks->onSuccess(SerializedScriptValue::nullValue());
    517452        return;
    518453    }
    519454
    520     RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(objectStore->m_backingStore.get(), range, direction, query.release(), IDBCursorBackendInterface::ObjectStoreCursor, transaction.get(), objectStore.get());
     455    RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(backingStoreCursor.release(), direction, IDBCursorBackendInterface::ObjectStoreCursor, transaction.get(), objectStore.get());
    521456    callbacks->onSuccess(cursor.release());
    522457}
     
    538473}
    539474
    540 SQLiteDatabase& IDBObjectStoreBackendImpl::sqliteDatabase() const
    541 {
    542     return m_backingStore->db();
    543 }
    544 
    545475void IDBObjectStoreBackendImpl::removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
    546476{
  • trunk/Source/WebCore/storage/IDBObjectStoreBackendImpl.h

    r79426 r80220  
    8383
    8484    void loadIndexes();
    85     SQLiteDatabase& sqliteDatabase() const;
    8685    PassRefPtr<IDBKey> genAutoIncrementKey();
    8786    void resetAutoIncrementKeyCache() { m_autoIncrementNumber = -1; }
Note: See TracChangeset for help on using the changeset viewer.