1/*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 *               2013 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 * THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "IDBIndexWriterLevelDB.h"
29
30#include "IDBKey.h"
31#include <wtf/text/CString.h>
32
33#if ENABLE(INDEXED_DATABASE)
34#if USE(LEVELDB)
35
36namespace WebCore {
37
38IDBIndexWriterLevelDB::IDBIndexWriterLevelDB(const IDBIndexMetadata& metadata, const IndexKeys& keys)
39    : m_indexMetadata(metadata)
40    , m_indexKeys(keys)
41{
42}
43
44void IDBIndexWriterLevelDB::writeIndexKeys(const IDBRecordIdentifier* recordIdentifier, IDBBackingStoreLevelDB& backingStore, IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId) const
45{
46    ASSERT(recordIdentifier);
47    int64_t indexId = m_indexMetadata.id;
48    for (size_t i = 0; i < m_indexKeys.size(); ++i) {
49        bool ok = backingStore.putIndexDataForRecord(transaction, databaseId, objectStoreId, indexId, *(m_indexKeys)[i].get(), recordIdentifier);
50        // This should have already been verified as a valid write during verifyIndexKeys.
51        ASSERT_UNUSED(ok, ok);
52    }
53}
54
55bool IDBIndexWriterLevelDB::verifyIndexKeys(IDBBackingStoreLevelDB& backingStore, IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId, bool& canAddKeys, const IDBKey* primaryKey, String* errorMessage) const
56{
57    canAddKeys = false;
58    for (size_t i = 0; i < m_indexKeys.size(); ++i) {
59        bool ok = addingKeyAllowed(backingStore, transaction, databaseId, objectStoreId, indexId, (m_indexKeys)[i].get(), primaryKey, canAddKeys);
60        if (!ok)
61            return false;
62        if (!canAddKeys) {
63            if (errorMessage)
64                *errorMessage = String::format("Unable to add key to index '%s': at least one key does not satisfy the uniqueness requirements.", m_indexMetadata.name.utf8().data());
65            return true;
66        }
67    }
68    canAddKeys = true;
69    return true;
70}
71
72bool IDBIndexWriterLevelDB::addingKeyAllowed(IDBBackingStoreLevelDB& backingStore, IDBBackingStoreTransactionLevelDB& transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey* indexKey, const IDBKey* primaryKey, bool& allowed) const
73{
74    allowed = false;
75    if (!m_indexMetadata.unique) {
76        allowed = true;
77        return true;
78    }
79
80    RefPtr<IDBKey> foundPrimaryKey;
81    bool found = false;
82    bool ok = backingStore.keyExistsInIndex(transaction, databaseId, objectStoreId, indexId, *indexKey, foundPrimaryKey, found);
83    if (!ok)
84        return false;
85    if (!found || (primaryKey && foundPrimaryKey->isEqual(primaryKey)))
86        allowed = true;
87    return true;
88}
89
90
91} // namespace WebCore
92
93#endif // USE(LEVELDB)
94#endif // ENABLE(INDEXED_DATABASE)
95