示例#1
0
void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
{
    if (transactionPtr->mode() == IDBTransaction::READ_ONLY) {
        ec = IDBDatabaseException::READ_ONLY_ERR;
        return;
    }

    RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
    RefPtr<SerializedScriptValue> value = prpValue;
    RefPtr<IDBKey> key = prpKey;
    RefPtr<IDBCallbacks> callbacks = prpCallbacks;
    RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;

    if (putMode != CursorUpdate) {
        if (key && !key->valid()) {
            ec = IDBDatabaseException::DATA_ERR;
            return;
        }
        const bool autoIncrement = objectStore->autoIncrement();
        const bool hasKeyPath = !objectStore->m_keyPath.isNull();
        if (!key && !autoIncrement && !hasKeyPath) {
            ec = IDBDatabaseException::DATA_ERR;
            return;
        }
        if (hasKeyPath) {
            if (key) {
                ec = IDBDatabaseException::DATA_ERR;
                return;
            }

            RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
            if (!autoIncrement) {
                if (!keyPathKey || !keyPathKey->valid()) {
                    ec = IDBDatabaseException::DATA_ERR;
                    return;
                }
            } else if (keyPathKey && !keyPathKey->valid()) {
                ec = IDBDatabaseException::DATA_ERR;
                return;
            }
        }
        for (IndexMap::iterator it = m_indexes.begin(); it != m_indexes.end(); ++it) {
            const RefPtr<IDBIndexBackendImpl>& index = it->second;
            RefPtr<IDBKey> indexKey = fetchKeyFromKeyPath(value.get(), index->keyPath());
            if (indexKey && !indexKey->valid()) {
                ec = IDBDatabaseException::DATA_ERR;
                return;
            }
        }
    }

    if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::putInternal, objectStore, value, key, putMode, callbacks, transaction)))
        ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
}
示例#2
0
PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::selectKeyForPut(IDBObjectStoreBackendImpl* objectStore, IDBKey* key, PutMode putMode, IDBCallbacks* callbacks, RefPtr<SerializedScriptValue>& value)
{
    if (putMode == CursorUpdate)
        ASSERT(key);

    const bool autoIncrement = objectStore->autoIncrement();
    const bool hasKeyPath = !objectStore->m_keyPath.isNull();

    if (autoIncrement && key) {
        objectStore->resetAutoIncrementKeyCache();
        return key;
    }

    if (autoIncrement) {
        ASSERT(!key);
        if (!hasKeyPath)
            return objectStore->genAutoIncrementKey();

        RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
        if (keyPathKey) {
            objectStore->resetAutoIncrementKeyCache();
            return keyPathKey;
        }

        RefPtr<IDBKey> autoIncKey = objectStore->genAutoIncrementKey();
        RefPtr<SerializedScriptValue> valueAfterInjection = injectKeyIntoKeyPath(autoIncKey, value, objectStore->m_keyPath);
        if (!valueAfterInjection) {
            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "The generated key could not be inserted into the object using the keyPath."));
            return 0;
        }
        value = valueAfterInjection;
        return autoIncKey.release();
    }

    if (hasKeyPath) {
        RefPtr<IDBKey> keyPathKey = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);

        // FIXME: This check should be moved to put() and raise an exception. WK76952
        if (putMode == CursorUpdate && !keyPathKey->isEqual(key)) {
            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "The key fetched from the keyPath does not match the key of the cursor."));
            return 0;
        }

        return keyPathKey.release();
    }

    if (!key) {
        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "No key supplied"));
        return 0;
    }

    return key;
}
示例#3
0
void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
{
    RefPtr<SerializedScriptValue> value = prpValue;
    RefPtr<IDBKey> key = selectKeyForPut(objectStore.get(), prpKey.get(), putMode, callbacks.get(), value);
    if (!key)
        return;
    ASSERT(key->valid());

    Vector<RefPtr<IDBKey> > indexKeys;
    for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
        const RefPtr<IDBIndexBackendImpl>& index = it->second;

        RefPtr<IDBKey> indexKey = fetchKeyFromKeyPath(value.get(), index->keyPath());
        if (!indexKey) {
            indexKeys.append(indexKey.release());
            continue;
        }
        ASSERT(indexKey->valid());

        if ((!index->multiEntry() || indexKey->type() != IDBKey::ArrayType) && !index->addingKeyAllowed(indexKey.get(), key.get())) {
            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "One of the derived (from a keyPath) keys for an index does not satisfy its uniqueness requirements."));
            return;
        }

       if (index->multiEntry() && indexKey->type() == IDBKey::ArrayType) {
           for (size_t j = 0; j < indexKey->array().size(); ++j) {
                if (!index->addingKeyAllowed(indexKey->array()[j].get(), key.get())) {
                    callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "One of the derived (from a keyPath) keys for an index does not satisfy its uniqueness requirements."));
                    return;
                }
            }
        }

        indexKeys.append(indexKey.release());
    }

    RefPtr<IDBBackingStore::ObjectStoreRecordIdentifier> recordIdentifier = objectStore->m_backingStore->createInvalidRecordIdentifier();
    bool isExistingValue = objectStore->m_backingStore->keyExistsInObjectStore(objectStore->m_databaseId, objectStore->id(), *key, recordIdentifier.get());

    if (putMode == AddOnly && isExistingValue) {
        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
        return;
    }

    // Before this point, don't do any mutation.  After this point, rollback the transaction in case of error.

    if (!objectStore->m_backingStore->putObjectStoreRecord(objectStore->m_databaseId, objectStore->id(), *key, value->toWireString(), recordIdentifier.get())) {
        // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
        transaction->abort();
        return;
    }

    int i = 0;
    for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it, ++i) {
        RefPtr<IDBIndexBackendImpl>& index = it->second;
        if (!index->hasValidId())
            continue; // The index object has been created, but does not exist in the database yet.

        if (!objectStore->m_backingStore->deleteIndexDataForRecord(objectStore->m_databaseId, objectStore->id(), index->id(), recordIdentifier.get())) {
            // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
            transaction->abort();
            return;
        }

        if (!indexKeys[i])
            continue;
        RefPtr<IDBKey> indexKey = indexKeys[i];

        if (!index->multiEntry() || indexKey->type() != IDBKey::ArrayType) {
            if (!objectStore->m_backingStore->putIndexDataForRecord(objectStore->m_databaseId, objectStore->id(), index->id(), *indexKey, recordIdentifier.get())) {
                // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
                callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
                transaction->abort();
                return;
            }
        } else {
            ASSERT(index->multiEntry());
            ASSERT(indexKey->type() == IDBKey::ArrayType);
            for (size_t j = 0; j < indexKey->array().size(); ++j) {
                if (!objectStore->m_backingStore->putIndexDataForRecord(objectStore->m_databaseId, objectStore->id(), index->id(), *indexKey->array()[j], recordIdentifier.get())) {
                    // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
                    callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
                    transaction->abort();
                    return;
                }
            }
        }
    }

    callbacks->onSuccess(key.get());
}
示例#4
0
void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, bool addOnly, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
{
    RefPtr<SerializedScriptValue> value = prpValue;
    RefPtr<IDBKey> key = prpKey;

    // FIXME: Support auto-increment.

    if (!objectStore->m_keyPath.isNull()) {
        if (key) {
            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "A key was supplied for an objectStore that has a keyPath."));
            return;
        }
        key = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
        if (!key) {
            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "The key could not be fetched from the keyPath."));
            return;
        }
    } else if (!key) {
        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "No key supplied."));
        return;
    }
    if (key->type() == IDBKey::NullType) {
        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "NULL key is not allowed."));
        return;
    }

    Vector<RefPtr<IDBKey> > indexKeys;
    for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
        RefPtr<IDBKey> key = fetchKeyFromKeyPath(value.get(), it->second->keyPath());
        if (!key) {
            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "The key could not be fetched from an index's keyPath."));
            return;
        }
        if (key->type() == IDBKey::NullType) {
            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::DATA_ERR, "One of the derived (from a keyPath) keys for an index is NULL."));
            return;
        }
        if (!it->second->addingKeyAllowed(key.get())) {
            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "One of the derived (from a keyPath) keys for an index does not satisfy its uniqueness requirements."));
            return;
        }
        indexKeys.append(key.release());
    }

    SQLiteStatement getQuery(objectStore->sqliteDatabase(), "SELECT id FROM ObjectStoreData " + whereClause(key.get()));
    bool ok = getQuery.prepare() == SQLResultOk;
    ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?

    bindWhereClause(getQuery, objectStore->id(), key.get());
    bool isExistingValue = getQuery.step() == SQLResultRow;
    if (addOnly && isExistingValue) {
        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
        return;
    }

    // Before this point, don't do any mutation.  After this point, rollback the transaction in case of error.

    int64_t dataRowId = isExistingValue ? getQuery.getColumnInt(0) : InvalidId;
    if (!putObjectStoreData(objectStore->sqliteDatabase(), key.get(), value.get(), objectStore->id(), dataRowId)) {
        // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
        transaction->abort();
        return;
    }

    if (!deleteIndexData(objectStore->sqliteDatabase(), dataRowId)) {
        // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
        callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
        transaction->abort();
        return;
    }

    int i = 0;
    for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it, ++i) {
        if (!putIndexData(objectStore->sqliteDatabase(), indexKeys[i].get(), it->second->id(), dataRowId)) {
            // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
            callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
            transaction->abort();
            return;
        }
    }

    callbacks->onSuccess(key.get());
}