1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "content/browser/indexed_db/indexed_db_index_writer.h" 6 7 #include "base/logging.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "content/browser/indexed_db/indexed_db_backing_store.h" 10 #include "content/browser/indexed_db/indexed_db_tracing.h" 11 #include "content/browser/indexed_db/indexed_db_transaction.h" 12 #include "content/common/indexed_db/indexed_db_key.h" 13 #include "content/common/indexed_db/indexed_db_key_path.h" 14 #include "content/common/indexed_db/indexed_db_key_range.h" 15 16 namespace content { 17 18 IndexWriter::IndexWriter( 19 const IndexedDBIndexMetadata& index_metadata) 20 : index_metadata_(index_metadata) {} 21 22 IndexWriter::IndexWriter( 23 const IndexedDBIndexMetadata& index_metadata, 24 const IndexedDBDatabase::IndexKeys& index_keys) 25 : index_metadata_(index_metadata), index_keys_(index_keys) {} 26 27 IndexWriter::~IndexWriter() {} 28 29 bool IndexWriter::VerifyIndexKeys( 30 IndexedDBBackingStore* backing_store, 31 IndexedDBBackingStore::Transaction* transaction, 32 int64 database_id, 33 int64 object_store_id, 34 int64 index_id, 35 bool* can_add_keys, 36 const IndexedDBKey& primary_key, 37 string16* error_message) const { 38 *can_add_keys = false; 39 for (size_t i = 0; i < index_keys_.size(); ++i) { 40 bool ok = AddingKeyAllowed(backing_store, 41 transaction, 42 database_id, 43 object_store_id, 44 index_id, 45 (index_keys_)[i], 46 primary_key, 47 can_add_keys); 48 if (!ok) 49 return false; 50 if (!*can_add_keys) { 51 if (error_message) 52 *error_message = ASCIIToUTF16("Unable to add key to index '") + 53 index_metadata_.name + 54 ASCIIToUTF16("': at least one key does not satisfy " 55 "the uniqueness requirements."); 56 return true; 57 } 58 } 59 *can_add_keys = true; 60 return true; 61 } 62 63 void IndexWriter::WriteIndexKeys( 64 const IndexedDBBackingStore::RecordIdentifier& record_identifier, 65 IndexedDBBackingStore* backing_store, 66 IndexedDBBackingStore::Transaction* transaction, 67 int64 database_id, 68 int64 object_store_id) const { 69 int64 index_id = index_metadata_.id; 70 for (size_t i = 0; i < index_keys_.size(); ++i) { 71 bool ok = backing_store->PutIndexDataForRecord(transaction, 72 database_id, 73 object_store_id, 74 index_id, 75 index_keys_[i], 76 record_identifier); 77 // This should have already been verified as a valid write during 78 // verify_index_keys. 79 DCHECK(ok); 80 } 81 } 82 83 bool IndexWriter::AddingKeyAllowed( 84 IndexedDBBackingStore* backing_store, 85 IndexedDBBackingStore::Transaction* transaction, 86 int64 database_id, 87 int64 object_store_id, 88 int64 index_id, 89 const IndexedDBKey& index_key, 90 const IndexedDBKey& primary_key, 91 bool* allowed) const { 92 *allowed = false; 93 if (!index_metadata_.unique) { 94 *allowed = true; 95 return true; 96 } 97 98 scoped_ptr<IndexedDBKey> found_primary_key; 99 bool found = false; 100 bool ok = backing_store->KeyExistsInIndex(transaction, 101 database_id, 102 object_store_id, 103 index_id, 104 index_key, 105 &found_primary_key, 106 &found); 107 if (!ok) 108 return false; 109 if (!found || 110 (primary_key.IsValid() && found_primary_key->IsEqual(primary_key))) 111 *allowed = true; 112 return true; 113 } 114 115 bool MakeIndexWriters( 116 scoped_refptr<IndexedDBTransaction> transaction, 117 IndexedDBBackingStore* backing_store, 118 int64 database_id, 119 const IndexedDBObjectStoreMetadata& object_store, 120 const IndexedDBKey& primary_key, // makes a copy 121 bool key_was_generated, 122 const std::vector<int64>& index_ids, 123 const std::vector<IndexedDBDatabase::IndexKeys>& index_keys, 124 ScopedVector<IndexWriter>* index_writers, 125 string16* error_message, 126 bool* completed) { 127 DCHECK_EQ(index_ids.size(), index_keys.size()); 128 *completed = false; 129 130 std::map<int64, IndexedDBDatabase::IndexKeys> index_key_map; 131 for (size_t i = 0; i < index_ids.size(); ++i) 132 index_key_map[index_ids[i]] = index_keys[i]; 133 134 for (IndexedDBObjectStoreMetadata::IndexMap::const_iterator it = 135 object_store.indexes.begin(); 136 it != object_store.indexes.end(); 137 ++it) { 138 const IndexedDBIndexMetadata& index = it->second; 139 140 IndexedDBDatabase::IndexKeys keys = index_key_map[it->first]; 141 // If the object_store is using auto_increment, then any indexes with an 142 // identical key_path need to also use the primary (generated) key as a key. 143 if (key_was_generated && (index.key_path == object_store.key_path)) 144 keys.push_back(primary_key); 145 146 scoped_ptr<IndexWriter> index_writer(new IndexWriter(index, keys)); 147 bool can_add_keys = false; 148 bool backing_store_success = 149 index_writer->VerifyIndexKeys(backing_store, 150 transaction->BackingStoreTransaction(), 151 database_id, 152 object_store.id, 153 index.id, 154 &can_add_keys, 155 primary_key, 156 error_message); 157 if (!backing_store_success) 158 return false; 159 if (!can_add_keys) 160 return true; 161 162 index_writers->push_back(index_writer.release()); 163 } 164 165 *completed = true; 166 return true; 167 } 168 169 } // namespace content 170