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