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 base::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 } 57 return true; 58 } 59 } 60 *can_add_keys = true; 61 return true; 62 } 63 64 void IndexWriter::WriteIndexKeys( 65 const IndexedDBBackingStore::RecordIdentifier& record_identifier, 66 IndexedDBBackingStore* backing_store, 67 IndexedDBBackingStore::Transaction* transaction, 68 int64 database_id, 69 int64 object_store_id) const { 70 int64 index_id = index_metadata_.id; 71 for (size_t i = 0; i < index_keys_.size(); ++i) { 72 bool ok = backing_store->PutIndexDataForRecord(transaction, 73 database_id, 74 object_store_id, 75 index_id, 76 index_keys_[i], 77 record_identifier); 78 // This should have already been verified as a valid write during 79 // verify_index_keys. 80 DCHECK(ok); 81 } 82 } 83 84 bool IndexWriter::AddingKeyAllowed( 85 IndexedDBBackingStore* backing_store, 86 IndexedDBBackingStore::Transaction* transaction, 87 int64 database_id, 88 int64 object_store_id, 89 int64 index_id, 90 const IndexedDBKey& index_key, 91 const IndexedDBKey& primary_key, 92 bool* allowed) const { 93 *allowed = false; 94 if (!index_metadata_.unique) { 95 *allowed = true; 96 return true; 97 } 98 99 scoped_ptr<IndexedDBKey> found_primary_key; 100 bool found = false; 101 bool ok = backing_store->KeyExistsInIndex(transaction, 102 database_id, 103 object_store_id, 104 index_id, 105 index_key, 106 &found_primary_key, 107 &found); 108 if (!ok) 109 return false; 110 if (!found || 111 (primary_key.IsValid() && found_primary_key->IsEqual(primary_key))) 112 *allowed = true; 113 return true; 114 } 115 116 bool MakeIndexWriters( 117 scoped_refptr<IndexedDBTransaction> transaction, 118 IndexedDBBackingStore* backing_store, 119 int64 database_id, 120 const IndexedDBObjectStoreMetadata& object_store, 121 const IndexedDBKey& primary_key, // makes a copy 122 bool key_was_generated, 123 const std::vector<int64>& index_ids, 124 const std::vector<IndexedDBDatabase::IndexKeys>& index_keys, 125 ScopedVector<IndexWriter>* index_writers, 126 base::string16* error_message, 127 bool* completed) { 128 DCHECK_EQ(index_ids.size(), index_keys.size()); 129 *completed = false; 130 131 std::map<int64, IndexedDBDatabase::IndexKeys> index_key_map; 132 for (size_t i = 0; i < index_ids.size(); ++i) 133 index_key_map[index_ids[i]] = index_keys[i]; 134 135 for (IndexedDBObjectStoreMetadata::IndexMap::const_iterator it = 136 object_store.indexes.begin(); 137 it != object_store.indexes.end(); 138 ++it) { 139 const IndexedDBIndexMetadata& index = it->second; 140 141 IndexedDBDatabase::IndexKeys keys = index_key_map[it->first]; 142 // If the object_store is using auto_increment, then any indexes with an 143 // identical key_path need to also use the primary (generated) key as a key. 144 if (key_was_generated && (index.key_path == object_store.key_path)) 145 keys.push_back(primary_key); 146 147 scoped_ptr<IndexWriter> index_writer(new IndexWriter(index, keys)); 148 bool can_add_keys = false; 149 bool backing_store_success = 150 index_writer->VerifyIndexKeys(backing_store, 151 transaction->BackingStoreTransaction(), 152 database_id, 153 object_store.id, 154 index.id, 155 &can_add_keys, 156 primary_key, 157 error_message); 158 if (!backing_store_success) 159 return false; 160 if (!can_add_keys) 161 return true; 162 163 index_writers->push_back(index_writer.release()); 164 } 165 166 *completed = true; 167 return true; 168 } 169 170 } // namespace content 171