Home | History | Annotate | Download | only in indexed_db
      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