blob: 92e0ec9cfe39e42a417c3377419ef89c0f248f84 [file] [log] [blame]
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/indexed_db/indexed_db_index_writer.h"
#include <stddef.h>
#include <utility>
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "content/browser/indexed_db/indexed_db_backing_store.h"
#include "content/browser/indexed_db/indexed_db_tracing.h"
#include "content/browser/indexed_db/indexed_db_transaction.h"
#include "content/common/indexed_db/indexed_db_key_path.h"
#include "content/common/indexed_db/indexed_db_key_range.h"
using base::ASCIIToUTF16;
using blink::IndexedDBIndexKeys;
using blink::IndexedDBKey;
namespace content {
IndexWriter::IndexWriter(
const IndexedDBIndexMetadata& index_metadata)
: index_metadata_(index_metadata) {}
IndexWriter::IndexWriter(const IndexedDBIndexMetadata& index_metadata,
const IndexedDBIndexKeys& index_keys)
: index_metadata_(index_metadata), index_keys_(index_keys) {}
IndexWriter::~IndexWriter() {}
bool IndexWriter::VerifyIndexKeys(
IndexedDBBackingStore* backing_store,
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
bool* can_add_keys,
const IndexedDBKey& primary_key,
base::string16* error_message) const {
*can_add_keys = false;
DCHECK_EQ(index_id, index_keys_.first);
for (const auto& key : index_keys_.second) {
bool ok = AddingKeyAllowed(backing_store, transaction, database_id,
object_store_id, index_id, key, primary_key,
can_add_keys);
if (!ok)
return false;
if (!*can_add_keys) {
if (error_message) {
*error_message = ASCIIToUTF16("Unable to add key to index '") +
index_metadata_.name +
ASCIIToUTF16("': at least one key does not satisfy "
"the uniqueness requirements.");
}
return true;
}
}
*can_add_keys = true;
return true;
}
void IndexWriter::WriteIndexKeys(
const IndexedDBBackingStore::RecordIdentifier& record_identifier,
IndexedDBBackingStore* backing_store,
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id) const {
int64_t index_id = index_metadata_.id;
DCHECK_EQ(index_id, index_keys_.first);
for (const auto& key : index_keys_.second) {
leveldb::Status s = backing_store->PutIndexDataForRecord(
transaction, database_id, object_store_id, index_id, key,
record_identifier);
// This should have already been verified as a valid write during
// verify_index_keys.
DCHECK(s.ok());
}
}
bool IndexWriter::AddingKeyAllowed(
IndexedDBBackingStore* backing_store,
IndexedDBBackingStore::Transaction* transaction,
int64_t database_id,
int64_t object_store_id,
int64_t index_id,
const IndexedDBKey& index_key,
const IndexedDBKey& primary_key,
bool* allowed) const {
*allowed = false;
if (!index_metadata_.unique) {
*allowed = true;
return true;
}
std::unique_ptr<IndexedDBKey> found_primary_key;
bool found = false;
leveldb::Status s = backing_store->KeyExistsInIndex(transaction,
database_id,
object_store_id,
index_id,
index_key,
&found_primary_key,
&found);
if (!s.ok())
return false;
if (!found ||
(primary_key.IsValid() && found_primary_key->Equals(primary_key)))
*allowed = true;
return true;
}
bool MakeIndexWriters(IndexedDBTransaction* transaction,
IndexedDBBackingStore* backing_store,
int64_t database_id,
const IndexedDBObjectStoreMetadata& object_store,
const IndexedDBKey& primary_key, // makes a copy
bool key_was_generated,
const std::vector<IndexedDBIndexKeys>& index_keys,
std::vector<std::unique_ptr<IndexWriter>>* index_writers,
base::string16* error_message,
bool* completed) {
*completed = false;
for (const auto& it : index_keys) {
const auto& found = object_store.indexes.find(it.first);
if (found == object_store.indexes.end())
continue;
const IndexedDBIndexMetadata& index = found->second;
IndexedDBIndexKeys keys = it;
// If the object_store is using auto_increment, then any indexes with an
// identical key_path need to also use the primary (generated) key as a key.
if (key_was_generated && (index.key_path == object_store.key_path))
keys.second.push_back(primary_key);
std::unique_ptr<IndexWriter> index_writer(
std::make_unique<IndexWriter>(index, keys));
bool can_add_keys = false;
bool backing_store_success =
index_writer->VerifyIndexKeys(backing_store,
transaction->BackingStoreTransaction(),
database_id,
object_store.id,
index.id,
&can_add_keys,
primary_key,
error_message);
if (!backing_store_success)
return false;
if (!can_add_keys)
return true;
index_writers->push_back(std::move(index_writer));
}
*completed = true;
return true;
}
} // namespace content