1/* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 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 AND ITS CONTRIBUTORS "AS IS" AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "IDBObjectStoreBackendImpl.h" 28 29#if ENABLE(INDEXED_DATABASE) 30 31#include "IDBBackingStore.h" 32#include "IDBBindingUtilities.h" 33#include "IDBCallbacks.h" 34#include "IDBCursorBackendImpl.h" 35#include "IDBDatabaseBackendImpl.h" 36#include "IDBDatabaseException.h" 37#include "IDBKey.h" 38#include "IDBKeyPath.h" 39#include "IDBKeyRange.h" 40#include "IDBTracing.h" 41#include "IDBTransactionBackendImpl.h" 42#include <wtf/MathExtras.h> 43 44namespace WebCore { 45 46bool IDBObjectStoreBackendImpl::IndexWriter::verifyIndexKeys(IDBBackingStore& backingStore, IDBBackingStore::Transaction* transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId, bool& canAddKeys, const IDBKey* primaryKey, String* errorMessage) const 47{ 48 canAddKeys = false; 49 for (size_t i = 0; i < m_indexKeys.size(); ++i) { 50 bool ok = addingKeyAllowed(backingStore, transaction, databaseId, objectStoreId, indexId, (m_indexKeys)[i].get(), primaryKey, canAddKeys); 51 if (!ok) 52 return false; 53 if (!canAddKeys) { 54 if (errorMessage) 55 *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()); 56 return true; 57 } 58 } 59 canAddKeys = true; 60 return true; 61} 62 63void IDBObjectStoreBackendImpl::IndexWriter::writeIndexKeys(const IDBBackingStore::RecordIdentifier& recordIdentifier, IDBBackingStore& backingStore, IDBBackingStore::Transaction* transaction, int64_t databaseId, int64_t objectStoreId) const 64{ 65 int64_t indexId = m_indexMetadata.id; 66 for (size_t i = 0; i < m_indexKeys.size(); ++i) { 67 bool ok = backingStore.putIndexDataForRecord(transaction, databaseId, objectStoreId, indexId, *(m_indexKeys)[i].get(), recordIdentifier); 68 // This should have already been verified as a valid write during verifyIndexKeys. 69 ASSERT_UNUSED(ok, ok); 70 } 71} 72 73bool IDBObjectStoreBackendImpl::IndexWriter::addingKeyAllowed(IDBBackingStore& backingStore, IDBBackingStore::Transaction* transaction, int64_t databaseId, int64_t objectStoreId, int64_t indexId, const IDBKey* indexKey, const IDBKey* primaryKey, bool& allowed) const 74{ 75 allowed = false; 76 if (!m_indexMetadata.unique) { 77 allowed = true; 78 return true; 79 } 80 81 RefPtr<IDBKey> foundPrimaryKey; 82 bool found = false; 83 bool ok = backingStore.keyExistsInIndex(transaction, databaseId, objectStoreId, indexId, *indexKey, foundPrimaryKey, found); 84 if (!ok) 85 return false; 86 if (!found || (primaryKey && foundPrimaryKey->isEqual(primaryKey))) 87 allowed = true; 88 return true; 89} 90 91bool IDBObjectStoreBackendImpl::makeIndexWriters(PassRefPtr<IDBTransactionBackendImpl> transaction, IDBBackingStore* backingStore, int64_t databaseId, const IDBObjectStoreMetadata& objectStore, PassRefPtr<IDBKey> primaryKey, bool keyWasGenerated, const Vector<int64_t>& indexIds, const Vector<IDBDatabaseBackendInterface::IndexKeys>& indexKeys, Vector<OwnPtr<IndexWriter> >* indexWriters, String* errorMessage, bool& completed) 92{ 93 ASSERT(indexIds.size() == indexKeys.size()); 94 completed = false; 95 96 HashMap<int64_t, IDBDatabaseBackendInterface::IndexKeys> indexKeyMap; 97 for (size_t i = 0; i < indexIds.size(); ++i) 98 indexKeyMap.add(indexIds[i], indexKeys[i]); 99 100 for (IDBObjectStoreMetadata::IndexMap::const_iterator it = objectStore.indexes.begin(); it != objectStore.indexes.end(); ++it) { 101 102 const IDBIndexMetadata& index = it->value; 103 104 IDBDatabaseBackendInterface::IndexKeys keys = indexKeyMap.get(it->key); 105 // If the objectStore is using autoIncrement, then any indexes with an identical keyPath need to also use the primary (generated) key as a key. 106 if (keyWasGenerated && (index.keyPath == objectStore.keyPath)) 107 keys.append(primaryKey); 108 109 OwnPtr<IndexWriter> indexWriter(adoptPtr(new IndexWriter(index, keys))); 110 bool canAddKeys = false; 111 bool backingStoreSuccess = indexWriter->verifyIndexKeys(*backingStore, transaction->backingStoreTransaction(), databaseId, objectStore.id, index.id, canAddKeys, primaryKey.get(), errorMessage); 112 if (!backingStoreSuccess) 113 return false; 114 if (!canAddKeys) 115 return true; 116 117 indexWriters->append(indexWriter.release()); 118 } 119 120 completed = true; 121 return true; 122} 123 124PassRefPtr<IDBKey> IDBObjectStoreBackendImpl::generateKey(PassRefPtr<IDBBackingStore> backingStore, PassRefPtr<IDBTransactionBackendImpl> transaction, int64_t databaseId, int64_t objectStoreId) 125{ 126 const int64_t maxGeneratorValue = 9007199254740992LL; // Maximum integer storable as ECMAScript number. 127 int64_t currentNumber; 128 bool ok = backingStore->getKeyGeneratorCurrentNumber(transaction->backingStoreTransaction(), databaseId, objectStoreId, currentNumber); 129 if (!ok) { 130 LOG_ERROR("Failed to getKeyGeneratorCurrentNumber"); 131 return IDBKey::createInvalid(); 132 } 133 if (currentNumber < 0 || currentNumber > maxGeneratorValue) 134 return IDBKey::createInvalid(); 135 136 return IDBKey::createNumber(currentNumber); 137} 138 139bool IDBObjectStoreBackendImpl::updateKeyGenerator(PassRefPtr<IDBBackingStore> backingStore, PassRefPtr<IDBTransactionBackendImpl> transaction, int64_t databaseId, int64_t objectStoreId, const IDBKey* key, bool checkCurrent) 140{ 141 ASSERT(key && key->type() == IDBKey::NumberType); 142 return backingStore->maybeUpdateKeyGeneratorCurrentNumber(transaction->backingStoreTransaction(), databaseId, objectStoreId, static_cast<int64_t>(floor(key->number())) + 1, checkCurrent); 143} 144 145} // namespace WebCore 146 147#endif 148