Changeset 106387 in webkit


Ignore:
Timestamp:
Jan 31, 2012 1:39:33 PM (12 years ago)
Author:
jsbell@chromium.org
Message:

IndexedDB: IDBCursor.update() should raise exception if key changed
https://bugs.webkit.org/show_bug.cgi?id=76952

Source/WebCore:

Move the test from the async task to the synchronous call, per spec. Also re-ordered the tests
done during the synchronous call and the asynchronous task to follow the spec order.

Reviewed by Tony Chang.

Tests: storage/indexeddb/cursor-update.html

  • storage/IDBObjectStoreBackendImpl.cpp:

(WebCore::IDBObjectStoreBackendImpl::put): Added check during update() call, order checks per spec.
(WebCore::IDBObjectStoreBackendImpl::putInternal): Move effective key calculation inline.

  • storage/IDBObjectStoreBackendImpl.h: Removed selectKeyForPut method.

LayoutTests:

Reviewed by Tony Chang.

  • storage/indexeddb/cursor-update-expected.txt:
  • storage/indexeddb/cursor-update.html:
Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r106380 r106387  
     12012-01-31  Joshua Bell  <jsbell@chromium.org>
     2
     3        IndexedDB: IDBCursor.update() should raise exception if key changed
     4        https://bugs.webkit.org/show_bug.cgi?id=76952
     5
     6        Reviewed by Tony Chang.
     7
     8        * storage/indexeddb/cursor-update-expected.txt:
     9        * storage/indexeddb/cursor-update.html:
     10
    1112012-01-31  Ryosuke Niwa  <rniwa@webkit.org>
    212
  • trunk/LayoutTests/storage/indexeddb/cursor-update-expected.txt

    r98563 r106387  
    105105trans.objectStore('keyPathStore').openCursor(keyRange)
    106106keyPathUpdateCursor()
    107 event.target.result.update({id: 100 + counter, number: 100 + counter})
    108 PASS event.target.errorCode is webkitIDBDatabaseException.DATA_ERR
    109 event.preventDefault()
    110 event.target.source.update({id: counter, number: 100 + counter++})
     107Expecting exception from event.target.result.update({id: 100 + counter, number: 100 + counter})
     108PASS Exception was thrown.
     109PASS code is webkitIDBDatabaseException.DATA_ERR
     110event.target.result.update({id: counter, number: 100 + counter++})
    111111event.target.source.continue()
    112112keyPathUpdateCursor()
    113 event.target.result.update({id: 100 + counter, number: 100 + counter})
    114 PASS event.target.errorCode is webkitIDBDatabaseException.DATA_ERR
    115 event.preventDefault()
    116 event.target.source.update({id: counter, number: 100 + counter++})
     113Expecting exception from event.target.result.update({id: 100 + counter, number: 100 + counter})
     114PASS Exception was thrown.
     115PASS code is webkitIDBDatabaseException.DATA_ERR
     116event.target.result.update({id: counter, number: 100 + counter++})
    117117event.target.source.continue()
    118118keyPathUpdateCursor()
    119 event.target.result.update({id: 100 + counter, number: 100 + counter})
    120 PASS event.target.errorCode is webkitIDBDatabaseException.DATA_ERR
    121 event.preventDefault()
    122 event.target.source.update({id: counter, number: 100 + counter++})
     119Expecting exception from event.target.result.update({id: 100 + counter, number: 100 + counter})
     120PASS Exception was thrown.
     121PASS code is webkitIDBDatabaseException.DATA_ERR
     122event.target.result.update({id: counter, number: 100 + counter++})
    123123event.target.source.continue()
    124124keyPathUpdateCursor()
    125 event.target.result.update({id: 100 + counter, number: 100 + counter})
    126 PASS event.target.errorCode is webkitIDBDatabaseException.DATA_ERR
    127 event.preventDefault()
    128 event.target.source.update({id: counter, number: 100 + counter++})
     125Expecting exception from event.target.result.update({id: 100 + counter, number: 100 + counter})
     126PASS Exception was thrown.
     127PASS code is webkitIDBDatabaseException.DATA_ERR
     128event.target.result.update({id: counter, number: 100 + counter++})
    129129event.target.source.continue()
    130130keyPathUpdateCursor()
  • trunk/LayoutTests/storage/indexeddb/cursor-update.html

    r99258 r106387  
    164164    }
    165165
    166     request = evalAndLog("event.target.result.update({id: 100 + counter, number: 100 + counter})");
    167     request.onsuccess = unexpectedSuccessCallback;
    168     request.onerror = function() {
    169         shouldBe("event.target.errorCode", "webkitIDBDatabaseException.DATA_ERR");
    170 
    171         evalAndLog("event.preventDefault()");
    172 
    173         request = evalAndLog("event.target.source.update({id: counter, number: 100 + counter++})");
    174         request.onsuccess = function() { evalAndLog("event.target.source.continue()") };
    175         request.onerror = unexpectedErrorCallback;
    176     }
     166    evalAndExpectException("event.target.result.update({id: 100 + counter, number: 100 + counter})", "webkitIDBDatabaseException.DATA_ERR");
     167
     168    request = evalAndLog("event.target.result.update({id: counter, number: 100 + counter++})");
     169    request.onsuccess = function() { evalAndLog("event.target.source.continue()") };
     170    request.onerror = unexpectedErrorCallback;
    177171}
    178172
  • trunk/Source/WebCore/ChangeLog

    r106385 r106387  
     12012-01-31  Joshua Bell  <jsbell@chromium.org>
     2
     3        IndexedDB: IDBCursor.update() should raise exception if key changed
     4        https://bugs.webkit.org/show_bug.cgi?id=76952
     5
     6        Move the test from the async task to the synchronous call, per spec. Also re-ordered the tests
     7        done during the synchronous call and the asynchronous task to follow the spec order.
     8
     9        Reviewed by Tony Chang.
     10
     11        Tests: storage/indexeddb/cursor-update.html
     12
     13        * storage/IDBObjectStoreBackendImpl.cpp:
     14        (WebCore::IDBObjectStoreBackendImpl::put): Added check during update() call, order checks per spec.
     15        (WebCore::IDBObjectStoreBackendImpl::putInternal): Move effective key calculation inline.
     16        * storage/IDBObjectStoreBackendImpl.h: Removed selectKeyForPut method.
     17
    1182012-01-31  Anders Carlsson  <andersca@apple.com>
    219
  • trunk/Source/WebCore/storage/IDBObjectStoreBackendImpl.cpp

    r105891 r106387  
    133133
    134134    if (putMode != CursorUpdate) {
     135        const bool autoIncrement = objectStore->autoIncrement();
     136        const bool hasKeyPath = !objectStore->m_keyPath.isNull();
     137
     138        if (hasKeyPath && key) {
     139            ec = IDBDatabaseException::DATA_ERR;
     140            return;
     141        }
     142        if (!hasKeyPath && !autoIncrement && !key) {
     143            ec = IDBDatabaseException::DATA_ERR;
     144            return;
     145        }
     146        if (hasKeyPath) {
     147            RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
     148            if (keyPathKey && !keyPathKey->valid()) {
     149                ec = IDBDatabaseException::DATA_ERR;
     150                return;
     151            }
     152            if (!autoIncrement && !keyPathKey) {
     153                ec = IDBDatabaseException::DATA_ERR;
     154                return;
     155            }
     156        }
    135157        if (key && !key->valid()) {
    136158            ec = IDBDatabaseException::DATA_ERR;
    137159            return;
    138         }
    139         const bool autoIncrement = objectStore->autoIncrement();
    140         const bool hasKeyPath = !objectStore->m_keyPath.isNull();
    141         if (!key && !autoIncrement && !hasKeyPath) {
    142             ec = IDBDatabaseException::DATA_ERR;
    143             return;
    144         }
    145         if (hasKeyPath) {
    146             if (key) {
    147                 ec = IDBDatabaseException::DATA_ERR;
    148                 return;
    149             }
    150 
    151             RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
    152             if (!autoIncrement) {
    153                 if (!keyPathKey || !keyPathKey->valid()) {
    154                     ec = IDBDatabaseException::DATA_ERR;
    155                     return;
    156                 }
    157             } else if (keyPathKey && !keyPathKey->valid()) {
    158                 ec = IDBDatabaseException::DATA_ERR;
    159                 return;
    160             }
    161160        }
    162161        for (IndexMap::iterator it = m_indexes.begin(); it != m_indexes.end(); ++it) {
     
    168167            }
    169168        }
     169    } else {
     170        ASSERT(key);
     171        const bool hasKeyPath = !objectStore->m_keyPath.isNull();
     172        if (hasKeyPath) {
     173            RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
     174            if (!keyPathKey || !keyPathKey->isEqual(key.get())) {
     175                ec = IDBDatabaseException::DATA_ERR;
     176                return;
     177            }
     178        }
    170179    }
    171180
     
    174183}
    175184
    176 PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::selectKeyForPut(IDBObjectStoreBackendImpl* objectStore, IDBKey* key, PutMode putMode, IDBCallbacks* callbacks, RefPtr<SerializedScriptValue>& value)
    177 {
    178     if (putMode == CursorUpdate)
    179         ASSERT(key);
    180 
    181     const bool autoIncrement = objectStore->autoIncrement();
    182     const bool hasKeyPath = !objectStore->m_keyPath.isNull();
    183 
    184     if (autoIncrement && key) {
    185         objectStore->resetAutoIncrementKeyCache();
    186         return key;
    187     }
    188 
    189     if (autoIncrement) {
    190         ASSERT(!key);
    191         if (!hasKeyPath)
    192             return objectStore->genAutoIncrementKey();
    193 
    194         RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
    195         if (keyPathKey) {
    196             objectStore->resetAutoIncrementKeyCache();
    197             return keyPathKey;
    198         }
    199 
    200         RefPtr<IDBKey> autoIncKey = objectStore->genAutoIncrementKey();
    201         RefPtr<SerializedScriptValue> valueAfterInjection = injectKeyIntoKeyPath(autoIncKey, value, objectStore->m_keyPath);
    202         if (!valueAfterInjection) {
    203             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "The generated key could not be inserted into the object using the keyPath."));
    204             return 0;
    205         }
    206         value = valueAfterInjection;
    207         return autoIncKey.release();
    208     }
    209 
    210     if (hasKeyPath) {
    211         RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
    212 
    213         // FIXME: This check should be moved to put() and raise an exception. WK76952
    214         if (putMode == CursorUpdate && !keyPathKey->isEqual(key)) {
    215             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "The key fetched from the keyPath does not match the key of the cursor."));
    216             return 0;
    217         }
    218 
    219         return keyPathKey.release();
    220     }
    221 
    222     if (!key) {
    223         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "No key supplied"));
    224         return 0;
    225     }
    226 
    227     return key;
    228 }
    229 
    230185void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
    231186{
    232187    RefPtr<SerializedScriptValue> value = prpValue;
    233     RefPtr<IDBKey> key = selectKeyForPut(objectStore.get(), prpKey.get(), putMode, callbacks.get(), value);
    234     if (!key)
    235         return;
    236     ASSERT(key->valid());
     188    RefPtr<IDBKey> key = prpKey;
     189
     190    if (putMode != CursorUpdate) {
     191        const bool autoIncrement = objectStore->autoIncrement();
     192        const bool hasKeyPath = !objectStore->m_keyPath.isNull();
     193        if (hasKeyPath) {
     194            ASSERT(!key);
     195            RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
     196            if (keyPathKey)
     197                key = keyPathKey;
     198        }
     199        if (autoIncrement) {
     200            if (!key) {
     201                RefPtr<IDBKey> autoIncKey = objectStore->genAutoIncrementKey();
     202                if (hasKeyPath) {
     203                    // FIXME: Add checks in put() to ensure this will always succeed (apart from I/O errors).
     204                    // https://bugs.webkit.org/show_bug.cgi?id=77374
     205                    RefPtr<SerializedScriptValue> valueAfterInjection = injectKeyIntoKeyPath(autoIncKey, value, objectStore->m_keyPath);
     206                    if (!valueAfterInjection) {
     207                        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "The generated key could not be inserted into the object using the keyPath."));
     208                        return;
     209                    }
     210                    value = valueAfterInjection;
     211                }
     212                key = autoIncKey;
     213            } else {
     214                // FIXME: Logic to update generator state should go here. Currently it does a scan.
     215                objectStore->resetAutoIncrementKeyCache();
     216            }
     217        }
     218    }
     219
     220    ASSERT(key && key->valid());
     221
     222    RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = objectStore->m_backingStore->createInvalidRecordIdentifier();
     223    if (putMode == AddOnly && objectStore->m_backingStore->keyExistsInObjectStore(objectStore->m_databaseId, objectStore->id(), *key, recordIdentifier.get())) {
     224        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
     225        return;
     226    }
    237227
    238228    Vector<RefPtr<IDBKey> > indexKeys;
     
    262252
    263253        indexKeys.append(indexKey.release());
    264     }
    265 
    266     RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = objectStore->m_backingStore->createInvalidRecordIdentifier();
    267     bool isExistingValue = objectStore->m_backingStore->keyExistsInObjectStore(objectStore->m_databaseId, objectStore->id(), *key, recordIdentifier.get());
    268 
    269     if (putMode == AddOnly && isExistingValue) {
    270         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
    271         return;
    272254    }
    273255
  • trunk/Source/WebCore/storage/IDBObjectStoreBackendImpl.h

    r103100 r106387  
    8888    PassRefPtr<IDBKey> genAutoIncrementKey();
    8989    void resetAutoIncrementKeyCache() { m_autoIncrementNumber = -1; }
    90     static PassRefPtr<IDBKey> selectKeyForPut(IDBObjectStoreBackendImpl*, IDBKey*, PutMode, IDBCallbacks*, RefPtr<SerializedScriptValue>&);
    9190
    9291    static void getInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>);
Note: See TracChangeset for help on using the changeset viewer.