Exemple #1
0
void MemoryObjectStore::getAllRecords(const IDBKeyRangeData& keyRangeData, std::optional<uint32_t> count, IndexedDB::GetAllType type, IDBGetAllResult& result) const
{
    result = { type };

    uint32_t targetCount;
    if (count && count.value())
        targetCount = count.value();
    else
        targetCount = std::numeric_limits<uint32_t>::max();

    IDBKeyRangeData range = keyRangeData;
    uint32_t currentCount = 0;
    while (currentCount < targetCount) {
        IDBKeyData key = lowestKeyWithRecordInRange(range);
        if (key.isNull())
            return;

        range.lowerKey = key;
        range.lowerOpen = true;

        if (type == IndexedDB::GetAllType::Keys)
            result.addKey(WTFMove(key));
        else
            result.addValue(valueForKey(key));

        ++currentCount;
    }
}
Exemple #2
0
IndexValueStore::Iterator IndexValueStore::reverseFind(const IDBKeyData& key, const IDBKeyData& primaryKey, CursorDuplicity duplicity)
{
    ASSERT(!key.isNull());
    ASSERT(!primaryKey.isNull());

    IDBKeyRangeData range;
    range.upperKey = key;
    range.upperOpen = false;

    auto iterator = highestReverseIteratorInRange(range);
    if (iterator == m_orderedKeys.rend())
        return { };

    auto record = m_records.get(*iterator);
    ASSERT(record);

    auto primaryIterator = record->reverseFind(primaryKey, duplicity);
    if (primaryIterator.isValid())
        return { *this, duplicity, iterator, primaryIterator };

    // If we didn't find a primary key iterator in this entry,
    // we need to move on to start of the next record.
    iterator++;
    if (iterator == m_orderedKeys.rend())
        return { };

    record = m_records.get(*iterator);
    ASSERT(record);

    primaryIterator = record->reverseBegin(duplicity);
    ASSERT(primaryIterator.isValid());

    return { *this, duplicity, iterator, primaryIterator };
}
void MemoryObjectStoreCursor::iterate(const IDBKeyData& key, uint32_t count, IDBGetResult& outData)
{
    LOG(IndexedDB, "MemoryObjectStoreCursor::iterate to key %s", key.loggingString().utf8().data());

    if (!m_objectStore.orderedKeys()) {
        m_currentPositionKey = { };
        outData = { };
        return;
    }

    if (key.isValid() && !m_info.range().containsKey(key)) {
        m_currentPositionKey = { };
        outData = { };
        return;
    }

    auto* set = m_objectStore.orderedKeys();
    if (set) {
        if (m_info.isDirectionForward())
            incrementForwardIterator(*set, key, count);
        else
            incrementReverseIterator(*set, key, count);
    }

    m_currentPositionKey = { };

    if (!hasValidPosition()) {
        outData = { };
        return;
    }

    currentData(outData);
}
Exemple #4
0
void UniqueIDBDatabase::performPutOrAdd(uint64_t callbackIdentifier, const IDBResourceIdentifier& transactionIdentifier, uint64_t objectStoreIdentifier, const IDBKeyData& keyData, const ThreadSafeDataBuffer& valueData, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
{
    ASSERT(!isMainThread());
    LOG(IndexedDB, "(db) UniqueIDBDatabase::performPutOrAdd");

    ASSERT(m_backingStore);
    ASSERT(objectStoreIdentifier);

    IDBKeyData usedKey;
    IDBError error;

    auto objectStoreInfo = m_databaseInfo->infoForExistingObjectStore(objectStoreIdentifier);
    if (!objectStoreInfo) {
        error = IDBError(IDBExceptionCode::InvalidStateError, ASCIILiteral("Object store cannot be found in the backing store"));
        m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
        return;
    }

    if (objectStoreInfo->autoIncrement() && !keyData.isValid()) {
        uint64_t keyNumber;
        error = m_backingStore->generateKeyNumber(transactionIdentifier, objectStoreIdentifier, keyNumber);
        if (!error.isNull()) {
            m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
            return;
        }
        
        usedKey.setNumberValue(keyNumber);
    } else
        usedKey = keyData;

    if (overwriteMode == IndexedDB::ObjectStoreOverwriteMode::NoOverwrite) {
        bool keyExists;
        error = m_backingStore->keyExistsInObjectStore(transactionIdentifier, objectStoreIdentifier, usedKey, keyExists);
        if (error.isNull() && keyExists)
            error = IDBError(IDBExceptionCode::ConstraintError, ASCIILiteral("Key already exists in the object store"));

        if (!error.isNull()) {
            m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
            return;
        }
    }

    // 3.4.1 Object Store Storage Operation
    // ...If a record already exists in store ...
    // then remove the record from store using the steps for deleting records from an object store...
    // This is important because formally deleting it from from the object store also removes it from the appropriate indexes.
    error = m_backingStore->deleteRange(transactionIdentifier, objectStoreIdentifier, usedKey);
    if (!error.isNull()) {
        m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
        return;
    }

    error = m_backingStore->addRecord(transactionIdentifier, objectStoreIdentifier, usedKey, valueData);

    m_server.postDatabaseTaskReply(createCrossThreadTask(*this, &UniqueIDBDatabase::didPerformPutOrAdd, callbackIdentifier, error, usedKey));
}
ThreadSafeDataBuffer MemoryObjectStore::valueForKeyRange(const IDBKeyRangeData& keyRangeData) const
{
    LOG(IndexedDB, "MemoryObjectStore::valueForKey");

    IDBKeyData key = lowestKeyWithRecordInRange(keyRangeData);
    if (key.isNull())
        return ThreadSafeDataBuffer();

    ASSERT(m_keyValueStore);
    return m_keyValueStore->get(key);
}
bool SQLiteIDBCursor::advanceUnique()
{
    IDBKeyData currentKey = m_currentKey;

    while (!m_completed) {
        if (!advanceOnce())
            return false;

        // If the new current key is different from the old current key, we're done.
        if (currentKey.compare(m_currentKey))
            return true;
    }

    return false;
}
bool injectIDBKeyIntoScriptValue(JSC::ExecState& exec, const IDBKeyData& keyData, JSC::JSValue value, const IDBKeyPath& keyPath)
{
    LOG(IndexedDB, "injectIDBKeyIntoScriptValue");

    ASSERT(keyPath.type() == IndexedDB::KeyPathType::String);

    Vector<String> keyPathElements;
    IDBKeyPathParseError error;
    IDBParseKeyPath(keyPath.string(), keyPathElements, error);
    ASSERT(error == IDBKeyPathParseError::None);

    if (keyPathElements.isEmpty())
        return false;

    JSValue parent = ensureNthValueOnKeyPath(&exec, value, keyPathElements, keyPathElements.size() - 1);
    if (parent.isUndefined())
        return false;

    auto key = keyData.maybeCreateIDBKey();
    if (!key)
        return false;

    if (!set(&exec, parent, keyPathElements.last(), idbKeyToJSValue(&exec, exec.lexicalGlobalObject(), key.get())))
        return false;

    return true;
}
bool injectIDBKeyIntoScriptValue(ExecState& exec, const IDBKeyData& keyData, JSValue value, const IDBKeyPath& keyPath)
{
    LOG(IndexedDB, "injectIDBKeyIntoScriptValue");

    ASSERT(WTF::holds_alternative<String>(keyPath));

    Vector<String> keyPathElements;
    IDBKeyPathParseError error;
    IDBParseKeyPath(WTF::get<String>(keyPath), keyPathElements, error);
    ASSERT(error == IDBKeyPathParseError::None);

    if (keyPathElements.isEmpty())
        return false;

    JSValue parent = ensureNthValueOnKeyPath(exec, value, keyPathElements, keyPathElements.size() - 1);
    if (parent.isUndefined())
        return false;

    auto key = keyData.maybeCreateIDBKey();
    if (!key)
        return false;

    if (!set(exec, parent, keyPathElements.last(), toJS(exec, *exec.lexicalGlobalObject(), key.get())))
        return false;

    return true;
}
JSC::JSValue toJS(JSC::ExecState* state, JSDOMGlobalObject* globalObject, const IDBKeyData& keyData)
{
    ASSERT(state);
    ASSERT(globalObject);

    return toJS(*state, *globalObject, keyData.maybeCreateIDBKey().get());
}
void MemoryObjectStoreCursor::incrementReverseIterator(std::set<IDBKeyData>& set, const IDBKeyData& key, uint32_t count)
{
    // We might need to re-grab the current iterator.
    // e.g. If the record it was pointed to had been deleted.
    bool didResetIterator = false;
    if (!m_iterator) {
        if (!m_currentPositionKey.isValid())
            return;

        m_remainingRange.upperKey = m_currentPositionKey;
        m_remainingRange.upperOpen = false;
        setFirstInRemainingRange(set);

        didResetIterator = true;
    }

    if (*m_iterator == set.end())
        return;

    if (key.isValid()) {
        // If iterating to a key, the count passed in must be zero, as there is no way to iterate by both a count and to a key.
        ASSERT(!count);

        if (!m_info.range().containsKey(key))
            return;

        if ((*m_iterator)->compare(key) > 0) {
            m_remainingRange.upperKey = key;
            m_remainingRange.upperOpen = false;

            setFirstInRemainingRange(set);
        }

        return;
    }

    if (!count)
        count = 1;

    // If the reverseIterator was reset because it's previous record had been deleted,
    // we might have already advanced past the current position, eating one one of the iteration counts.
    if (didResetIterator && (*m_iterator)->compare(m_currentPositionKey) < 0)
        --count;

    while (count) {
        if (*m_iterator == set.begin()) {
            m_iterator = Nullopt;
            return;
        }

        --count;
        --*m_iterator;

        if (!m_info.range().containsKey(**m_iterator)) {
            m_iterator = Nullopt;
            return;
        }
    }
}
Exemple #11
0
IndexValueStore::Iterator IndexValueStore::find(const IDBKeyData& key, const IDBKeyData& primaryKey)
{
    ASSERT(!key.isNull());
    ASSERT(!primaryKey.isNull());

    IDBKeyRangeData range;
    range.lowerKey = key;
    range.lowerOpen = false;

    auto iterator = lowestIteratorInRange(range);
    if (iterator == m_orderedKeys.end())
        return { };

    auto record = m_records.get(*iterator);
    ASSERT(record);

    // If the main record iterator is not equal to the key we were looking for,
    // we know the primary key record should be the first.
    if (*iterator != key) {
        auto primaryIterator = record->begin();
        ASSERT(primaryIterator.isValid());

        return { *this, iterator, primaryIterator };
    }

    auto primaryIterator = record->find(primaryKey);
    if (primaryIterator.isValid())
        return { *this, iterator, primaryIterator };

    // If we didn't find a primary key iterator in this entry,
    // we need to move on to start of the next record.
    iterator++;
    if (iterator == m_orderedKeys.end())
        return { };

    record = m_records.get(*iterator);
    ASSERT(record);

    primaryIterator = record->begin();
    ASSERT(primaryIterator.isValid());

    return { *this, iterator, primaryIterator };
}
Exemple #12
0
IDBGetResult MemoryIndex::getResultForKeyRange(IndexedDB::IndexRecordType type, const IDBKeyRangeData& range) const
{
    LOG(IndexedDB, "MemoryIndex::getResultForKeyRange");

    if (!m_records)
        return { };

    IDBKeyData keyToLookFor;
    if (range.isExactlyOneKey())
        keyToLookFor = range.lowerKey;
    else
        keyToLookFor = m_records->lowestKeyWithRecordInRange(range);

    if (keyToLookFor.isNull())
        return { };

    const IDBKeyData* keyValue = m_records->lowestValueForKey(keyToLookFor);

    if (!keyValue)
        return { };

    return type == IndexedDB::IndexRecordType::Key ? IDBGetResult(*keyValue) : IDBGetResult(m_objectStore.valueForKeyRange(*keyValue));
}
Exemple #13
0
RefPtr<SharedBuffer> serializeIDBKeyData(const IDBKeyData& key)
{
#if USE(CF)
    Vector<char> data;
    data.append(SIDBKeyVersion);

    encodeKey(data, key);
    return SharedBuffer::adoptVector(data);
#else
    auto encoder = KeyedEncoder::encoder();
    key.encode(*encoder);
    return encoder->finishEncoding();
#endif

}
Exemple #14
0
IndexValueStore::Iterator IndexValueStore::find(const IDBKeyData& key, bool open)
{
    IDBKeyRangeData range;
    if (!key.isNull())
        range.lowerKey = key;
    else
        range.lowerKey = IDBKeyData::minimum();
    range.lowerOpen = open;

    auto iterator = lowestIteratorInRange(range);
    if (iterator == m_orderedKeys.end())
        return { };

    auto record = m_records.get(*iterator);
    ASSERT(record);

    auto primaryIterator = record->begin();
    ASSERT(primaryIterator.isValid());
    return { *this, iterator, primaryIterator };
}
Exemple #15
0
IndexValueStore::Iterator IndexValueStore::reverseFind(const IDBKeyData& key, CursorDuplicity duplicity, bool open)
{
    IDBKeyRangeData range;
    if (!key.isNull())
        range.upperKey = key;
    else
        range.upperKey = IDBKeyData::maximum();
    range.upperOpen = open;

    auto iterator = highestReverseIteratorInRange(range);
    if (iterator == m_orderedKeys.rend())
        return { };

    auto record = m_records.get(*iterator);
    ASSERT(record);

    auto primaryIterator = record->reverseBegin(duplicity);
    ASSERT(primaryIterator.isValid());
    return { *this, duplicity, iterator, primaryIterator };
}
Exemple #16
0
void IDBCursor::continueFunction(const IDBKeyData& key, ExceptionCodeWithMessage& ec)
{
    LOG(IndexedDB, "IDBCursor::continueFunction");

    if (!m_request) {
        ec.code = IDBDatabaseException::InvalidStateError;
        return;
    }

    if (sourcesDeleted()) {
        ec.code = IDBDatabaseException::InvalidStateError;
        return;
    }

    if (!transaction().isActive()) {
        ec.code = IDBDatabaseException::TransactionInactiveError;
        ec.message = ASCIILiteral("Failed to execute 'continue' on 'IDBCursor': The transaction is inactive or finished.");
        return;
    }

    if (!m_gotValue) {
        ec.code = IDBDatabaseException::InvalidStateError;
        ec.message = ASCIILiteral("Failed to execute 'continue' on 'IDBCursor': The cursor is being iterated or has iterated past its end.");
        return;
    }

    if (!key.isNull() && !key.isValid()) {
        ec.code = IDBDatabaseException::DataError;
        ec.message = ASCIILiteral("Failed to execute 'continue' on 'IDBCursor': The parameter is not a valid key.");
        return;
    }

    if (m_info.isDirectionForward()) {
        if (!key.isNull() && key.compare(m_currentPrimaryKeyData) <= 0) {
            ec.code = IDBDatabaseException::DataError;
            ec.message = ASCIILiteral("Failed to execute 'continue' on 'IDBCursor': The parameter is less than or equal to this cursor's position.");
            return;
        }
    } else if (!key.isNull() && key.compare(m_currentPrimaryKeyData) >= 0) {
        ec.code = IDBDatabaseException::DataError;
        ec.message = ASCIILiteral("Failed to execute 'continue' on 'IDBCursor': The parameter is greater than or equal to this cursor's position.");
        return;
    }

    m_gotValue = false;

    uncheckedIteratorCursor(key, 0);
}
Exemple #17
0
static void encodeKey(Vector<char>& data, const IDBKeyData& key)
{
    SIDBKeyType type = serializedTypeForKeyType(key.type());
    data.append(static_cast<char>(type));

    switch (type) {
    case SIDBKeyType::Number:
        writeDouble(data, key.number());
        break;
    case SIDBKeyType::Date:
        writeDouble(data, key.date());
        break;
    case SIDBKeyType::String: {
        auto string = key.string();
        uint32_t length = string.length();
        writeLittleEndian(data, length);

        for (size_t i = 0; i < length; ++i)
            writeLittleEndian(data, string[i]);

        break;
    }
    case SIDBKeyType::Binary: {
        auto& buffer = key.binary();
        uint64_t size = buffer.size();
        writeLittleEndian(data, size);

        auto* bufferData = buffer.data();
        ASSERT(bufferData || !size);
        if (bufferData)
            data.append(bufferData->data(), bufferData->size());

        break;
    }
    case SIDBKeyType::Array: {
        auto& array = key.array();
        uint64_t size = array.size();
        writeLittleEndian(data, size);
        for (auto& key : array)
            encodeKey(data, key);

        break;
    }
    case SIDBKeyType::Min:
    case SIDBKeyType::Max:
        break;
    }
}
Exemple #18
0
void IDBCursor::continueFunction(const IDBKeyData& key, ExceptionCode& ec)
{
    LOG(IndexedDB, "IDBCursor::continueFunction");

    if (!m_request) {
        ec = IDBDatabaseException::InvalidStateError;
        return;
    }

    if (sourcesDeleted()) {
        ec = IDBDatabaseException::InvalidStateError;
        return;
    }

    if (!transaction().isActive()) {
        ec = IDBDatabaseException::TransactionInactiveError;
        return;
    }

    if (!m_gotValue) {
        ec = IDBDatabaseException::InvalidStateError;
        return;
    }

    if (!key.isNull() && !key.isValid()) {
        ec = IDBDatabaseException::DataError;
        return;
    }

    if (m_info.isDirectionForward()) {
        if (!key.isNull() && key.compare(m_currentPrimaryKeyData) <= 0) {
            ec = IDBDatabaseException::DataError;
            return;
        }
    } else if (!key.isNull() && key.compare(m_currentPrimaryKeyData) >= 0) {
        ec = IDBDatabaseException::DataError;
        return;
    }

    m_gotValue = false;

    uncheckedIteratorCursor(key, 0);
}
JSValue idbKeyDataToJSValue(JSC::ExecState& exec, const IDBKeyData& keyData)
{
    if (keyData.isNull())
        return jsUndefined();

    Locker<JSLock> locker(exec.vm().apiLock());

    switch (keyData.type()) {
    case KeyType::Array:
        {
            const Vector<IDBKeyData>& inArray = keyData.array();
            size_t size = inArray.size();
            JSArray* outArray = constructEmptyArray(&exec, 0, exec.lexicalGlobalObject(), size);
            for (size_t i = 0; i < size; ++i) {
                auto& arrayKey = inArray.at(i);
                outArray->putDirectIndex(&exec, i, idbKeyDataToJSValue(exec, arrayKey));
            }
            return JSValue(outArray);
        }
    case KeyType::String:
        return jsStringWithCache(&exec, keyData.string());
    case KeyType::Date:
        return jsDateOrNull(&exec, keyData.date());
    case KeyType::Number:
        return jsNumber(keyData.number());
    case KeyType::Min:
    case KeyType::Max:
    case KeyType::Invalid:
        ASSERT_NOT_REACHED();
        return jsUndefined();
    }

    ASSERT_NOT_REACHED();
    return jsUndefined();

}
Exemple #20
0
static bool decodeKey(const uint8_t*& data, const uint8_t* end, IDBKeyData& result)
{
    if (!data || data >= end)
        return false;

    SIDBKeyType type = static_cast<SIDBKeyType>(data++[0]);
    switch (type) {
    case SIDBKeyType::Min:
        result = IDBKeyData::minimum();
        return true;
    case SIDBKeyType::Max:
        result = IDBKeyData::maximum();
        return true;
    case SIDBKeyType::Number: {
        double d;
        if (!readDouble(data, end, d))
            return false;

        result.setNumberValue(d);
        return true;
    }
    case SIDBKeyType::Date: {
        double d;
        if (!readDouble(data, end, d))
            return false;

        result.setDateValue(d);
        return true;
    }
    case SIDBKeyType::String: {
        uint32_t length;
        if (!readLittleEndian(data, end, length))
            return false;

        if (static_cast<uint64_t>(end - data) < length * 2)
            return false;

        Vector<UChar> buffer;
        buffer.reserveInitialCapacity(length);
        for (size_t i = 0; i < length; i++) {
            uint16_t ch;
            if (!readLittleEndian(data, end, ch))
                return false;
            buffer.uncheckedAppend(ch);
        }

        result.setStringValue(String::adopt(WTFMove(buffer)));

        return true;
    }
    case SIDBKeyType::Binary: {
        uint64_t size64;
        if (!readLittleEndian(data, end, size64))
            return false;

        if (static_cast<uint64_t>(end - data) < size64)
            return false;

        if (size64 > std::numeric_limits<size_t>::max())
            return false;

        size_t size = static_cast<size_t>(size64);
        Vector<uint8_t> dataVector;

        dataVector.append(data, size);
        data += size;

        result.setBinaryValue(ThreadSafeDataBuffer::adoptVector(dataVector));
        return true;
    }
    case SIDBKeyType::Array: {
        uint64_t size64;
        if (!readLittleEndian(data, end, size64))
            return false;

        if (size64 > std::numeric_limits<size_t>::max())
            return false;

        size_t size = static_cast<size_t>(size64);
        Vector<IDBKeyData> array;
        array.reserveInitialCapacity(size);

        for (size_t i = 0; i < size; ++i) {
            IDBKeyData keyData;
            if (!decodeKey(data, end, keyData))
                return false;

            ASSERT(keyData.isValid());
            array.uncheckedAppend(WTFMove(keyData));
        }

        result.setArrayValue(array);

        return true;
    }
    default:
        LOG_ERROR("decodeKey encountered unexpected type: %i", (int)type);
        return false;
    }
}
CrossThreadCopierBase<false, false, IDBKeyData>::Type CrossThreadCopierBase<false, false, IDBKeyData>::copy(const IDBKeyData& keyData)
{
    return keyData.isolatedCopy();
}
Deprecated::ScriptValue idbKeyDataToScriptValue(ScriptExecutionContext* context, const IDBKeyData& keyData)
{
    RefPtr<IDBKey> key = keyData.maybeCreateIDBKey();
    DOMRequestState requestState(context);
    return idbKeyToScriptValue(&requestState, key.get());
}