PassRefPtr<IDBIndex> IDBObjectStore::createIndex(const String& name, const IDBKeyPath& keyPath, const Dictionary& options, ExceptionCode& ec) { IDB_TRACE("IDBObjectStore::createIndex"); if (!m_transaction->isVersionChange() || m_deleted) { ec = IDBDatabaseException::IDB_INVALID_STATE_ERR; return 0; } if (!keyPath.isValid()) { ec = IDBDatabaseException::IDB_SYNTAX_ERR; return 0; } bool unique = false; options.get("unique", unique); bool multiEntry = false; options.get("multiEntry", multiEntry); if (keyPath.type() == IDBKeyPath::ArrayType && multiEntry) { ec = IDBDatabaseException::IDB_NOT_SUPPORTED_ERR; return 0; } RefPtr<IDBIndexBackendInterface> indexBackend = m_backend->createIndex(name, keyPath, unique, multiEntry, m_transaction->backend(), ec); ASSERT(!indexBackend != !ec); // If we didn't get an index, we should have gotten an exception code. And vice versa. if (ec) return 0; RefPtr<IDBIndex> index = IDBIndex::create(indexBackend.release(), this, m_transaction.get()); m_indexMap.set(name, index); return index.release(); }
RefPtr<IDBIndex> IDBObjectStore::createIndex(ScriptExecutionContext&, const String& name, const IDBKeyPath& keyPath, const IndexParameters& parameters, ExceptionCodeWithMessage& ec) { LOG(IndexedDB, "IDBObjectStore::createIndex %s", name.utf8().data()); ASSERT(currentThread() == m_transaction->database().originThreadID()); if (m_deleted) { ec.code = IDBDatabaseException::InvalidStateError; ec.message = ASCIILiteral("Failed to execute 'createIndex' on 'IDBObjectStore': The object store has been deleted."); return nullptr; } if (!m_transaction->isVersionChange()) { ec.code = IDBDatabaseException::InvalidStateError; ec.message = ASCIILiteral("Failed to execute 'createIndex' on 'IDBObjectStore': The database is not running a version change transaction."); return nullptr; } if (!m_transaction->isActive()) { ec.code = IDBDatabaseException::TransactionInactiveError; return nullptr; } if (!keyPath.isValid()) { ec.code = IDBDatabaseException::SyntaxError; ec.message = ASCIILiteral("Failed to execute 'createIndex' on 'IDBObjectStore': The keyPath argument contains an invalid key path."); return nullptr; } if (name.isNull()) { ec.code = TypeError; return nullptr; } if (m_info.hasIndex(name)) { ec.code = IDBDatabaseException::ConstraintError; ec.message = ASCIILiteral("Failed to execute 'createIndex' on 'IDBObjectStore': An index with the specified name already exists."); return nullptr; } if (keyPath.type() == IDBKeyPath::Type::Array && parameters.multiEntry) { ec.code = IDBDatabaseException::InvalidAccessError; ec.message = ASCIILiteral("Failed to execute 'createIndex' on 'IDBObjectStore': The keyPath argument was an array and the multiEntry option is true."); return nullptr; } // Install the new Index into the ObjectStore's info. IDBIndexInfo info = m_info.createNewIndex(name, keyPath, parameters.unique, parameters.multiEntry); m_transaction->database().didCreateIndexInfo(info); // Create the actual IDBObjectStore from the transaction, which also schedules the operation server side. auto index = m_transaction->createIndex(*this, info); RefPtr<IDBIndex> refIndex = index.get(); Locker<Lock> locker(m_referencedIndexLock); m_referencedIndexes.set(name, WTFMove(index)); return refIndex; }
RefPtr<WebCore::IDBIndex> IDBObjectStore::createIndex(ScriptExecutionContext* context, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, ExceptionCodeWithMessage& ec) { LOG(IndexedDB, "IDBObjectStore::createIndex %s", name.utf8().data()); if (!context) { ec.code = IDBDatabaseException::InvalidStateError; return nullptr; } if (m_deleted) { ec.code = IDBDatabaseException::InvalidStateError; return nullptr; } if (!m_transaction->isVersionChange()) { ec.code = IDBDatabaseException::InvalidStateError; ec.message = ASCIILiteral("Failed to execute 'createIndex' on 'IDBObjectStore': The database is not running a version change transaction."); return nullptr; } if (!m_transaction->isActive()) { ec.code = IDBDatabaseException::TransactionInactiveError; return nullptr; } if (!keyPath.isValid()) { ec.code = IDBDatabaseException::SyntaxError; ec.message = ASCIILiteral("Failed to execute 'createIndex' on 'IDBObjectStore': The keyPath argument contains an invalid key path."); return nullptr; } if (name.isNull()) { ec.code = TypeError; return nullptr; } if (m_info.hasIndex(name)) { ec.code = IDBDatabaseException::ConstraintError; ec.message = ASCIILiteral("Failed to execute 'createIndex' on 'IDBObjectStore': An index with the specified name already exists."); return nullptr; } if (keyPath.type() == IndexedDB::KeyPathType::Array && multiEntry) { ec.code = IDBDatabaseException::InvalidAccessError; ec.message = ASCIILiteral("Failed to execute 'createIndex' on 'IDBObjectStore': The keyPath argument was an array and the multiEntry option is true."); return nullptr; } // Install the new Index into the ObjectStore's info. IDBIndexInfo info = m_info.createNewIndex(name, keyPath, unique, multiEntry); m_transaction->database().didCreateIndexInfo(info); // Create the actual IDBObjectStore from the transaction, which also schedules the operation server side. Ref<IDBIndex> index = m_transaction->createIndex(*this, info); m_referencedIndexes.set(name, &index.get()); return WTF::move(index); }
PassRefPtr<IDBIndex> IDBObjectStore::createIndex(ScriptExecutionContext* context, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, ExceptionCode& ec) { IDB_TRACE("IDBObjectStore::createIndex"); if (!m_transaction->isVersionChange() || isDeleted()) { ec = IDBDatabaseException::InvalidStateError; return 0; } if (!m_transaction->isActive()) { ec = IDBDatabaseException::TransactionInactiveError; return 0; } if (!keyPath.isValid()) { ec = IDBDatabaseException::SyntaxError; return 0; } if (name.isNull()) { ec = TypeError; return 0; } if (containsIndex(name)) { ec = IDBDatabaseException::ConstraintError; return 0; } if (keyPath.type() == IDBKeyPath::ArrayType && multiEntry) { ec = IDBDatabaseException::InvalidAccessError; return 0; } int64_t indexId = m_metadata.maxIndexId + 1; backendDB()->createIndex(m_transaction->id(), id(), indexId, name, keyPath, unique, multiEntry); ++m_metadata.maxIndexId; IDBIndexMetadata metadata(name, indexId, keyPath, unique, multiEntry); RefPtr<IDBIndex> index = IDBIndex::create(metadata, this, m_transaction.get()); m_indexMap.set(name, index); m_metadata.indexes.set(indexId, metadata); m_transaction->db()->indexCreated(id(), metadata); ASSERT(!ec); if (ec) return 0; RefPtr<IDBRequest> indexRequest = openCursor(context, static_cast<IDBKeyRange*>(0), IDBCursor::directionNext(), IDBDatabaseBackendInterface::PreemptiveTask, ec); ASSERT(!ec); if (ec) return 0; indexRequest->preventPropagation(); // This is kept alive by being the success handler of the request, which is in turn kept alive by the owning transaction. RefPtr<IndexPopulator> indexPopulator = IndexPopulator::create(backendDB(), m_transaction->id(), id(), metadata); indexRequest->setOnsuccess(indexPopulator); return index.release(); }
PassRefPtr<IDBObjectStore> IDBDatabase::createObjectStore(const String& name, const Dictionary& options, ExceptionCode& ec) { if (!m_versionChangeTransaction) { ec = IDBDatabaseException::IDB_INVALID_STATE_ERR; return 0; } if (!m_versionChangeTransaction->isActive()) { ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR; return 0; } IDBKeyPath keyPath; if (!options.isUndefinedOrNull()) { String keyPathString; Vector<String> keyPathArray; if (options.get("keyPath", keyPathArray)) keyPath = IDBKeyPath(keyPathArray); else if (options.getWithUndefinedOrNullCheck("keyPath", keyPathString)) keyPath = IDBKeyPath(keyPathString); } if (containsObjectStore(name)) { ec = IDBDatabaseException::CONSTRAINT_ERR; return 0; } if (!keyPath.isNull() && !keyPath.isValid()) { ec = IDBDatabaseException::IDB_SYNTAX_ERR; return 0; } bool autoIncrement = false; if (!options.isUndefinedOrNull()) options.get("autoIncrement", autoIncrement); if (autoIncrement && ((keyPath.type() == IDBKeyPath::StringType && keyPath.string().isEmpty()) || keyPath.type() == IDBKeyPath::ArrayType)) { ec = IDBDatabaseException::IDB_INVALID_ACCESS_ERR; return 0; } int64_t objectStoreId = m_metadata.maxObjectStoreId + 1; RefPtr<IDBObjectStoreBackendInterface> objectStoreBackend = m_backend->createObjectStore(objectStoreId, name, keyPath, autoIncrement, m_versionChangeTransaction->backend(), ec); if (!objectStoreBackend) { ASSERT(ec); return 0; } IDBObjectStoreMetadata metadata(name, objectStoreId, keyPath, autoIncrement, IDBObjectStoreBackendInterface::MinimumIndexId); RefPtr<IDBObjectStore> objectStore = IDBObjectStore::create(metadata, objectStoreBackend.release(), m_versionChangeTransaction.get()); m_metadata.objectStores.set(metadata.id, metadata); ++m_metadata.maxObjectStoreId; m_versionChangeTransaction->objectStoreCreated(name, objectStore); return objectStore.release(); }
RefPtr<WebCore::IDBIndex> IDBObjectStore::createIndex(ScriptExecutionContext* context, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, ExceptionCode& ec) { LOG(IndexedDB, "IDBObjectStore::createIndex %s", name.utf8().data()); if (!context) { ec = INVALID_STATE_ERR; return nullptr; } if (m_deleted) { ec = static_cast<ExceptionCode>(IDBExceptionCode::InvalidStateError); return nullptr; } if (!m_transaction->isVersionChange()) { ec = static_cast<ExceptionCode>(IDBExceptionCode::InvalidStateError); return nullptr; } if (!m_transaction->isActive()) { ec = static_cast<ExceptionCode>(IDBExceptionCode::TransactionInactiveError); return nullptr; } if (!keyPath.isValid()) { ec = IDBDatabaseException::SyntaxError; return nullptr; } if (name.isNull()) { ec = TypeError; return nullptr; } if (m_info.hasIndex(name)) { ec = IDBDatabaseException::ConstraintError; return nullptr; } if (keyPath.type() == IndexedDB::KeyPathType::Array && multiEntry) { ec = IDBDatabaseException::InvalidAccessError; return nullptr; } // Install the new Index into the ObjectStore's info. IDBIndexInfo info = m_info.createNewIndex(name, keyPath, unique, multiEntry); m_transaction->database().didCreateIndexInfo(info); // Create the actual IDBObjectStore from the transaction, which also schedules the operation server side. Ref<IDBIndex> index = m_transaction->createIndex(*this, info); return WTF::move(index); }
PassRefPtr<IDBIndex> IDBObjectStore::createIndex(ScriptExecutionContext* context, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, ExceptionCode& ec) { LOG(StorageAPI, "IDBObjectStore::createIndex"); if (!m_transaction->isVersionChange() || m_deleted) { ec = IDBDatabaseException::InvalidStateError; return 0; } if (!m_transaction->isActive()) { ec = IDBDatabaseException::TransactionInactiveError; return 0; } if (!keyPath.isValid()) { ec = IDBDatabaseException::SyntaxError; return 0; } if (name.isNull()) { ec = TypeError; return 0; } if (containsIndex(name)) { ec = IDBDatabaseException::ConstraintError; return 0; } if (keyPath.type() == IDBKeyPath::ArrayType && multiEntry) { ec = IDBDatabaseException::InvalidAccessError; return 0; } int64_t indexId = m_metadata.maxIndexId + 1; backendDB()->createIndex(m_transaction->id(), id(), indexId, name, keyPath, unique, multiEntry); ++m_metadata.maxIndexId; IDBIndexMetadata metadata(name, indexId, keyPath, unique, multiEntry); RefPtr<IDBIndex> index = IDBIndex::create(metadata, this, m_transaction.get()); m_indexMap.set(name, index); m_metadata.indexes.set(indexId, metadata); ASSERT(!ec); if (ec) return 0; ASSERT_UNUSED(context, context); return index.release(); }
RefPtr<WebCore::IDBObjectStore> IDBDatabase::createObjectStore(const String& name, const IDBKeyPath& keyPath, bool autoIncrement, ExceptionCodeWithMessage& ec) { LOG(IndexedDB, "IDBDatabase::createObjectStore - (%s %s)", m_info.name().utf8().data(), name.utf8().data()); ASSERT(currentThread() == originThreadID()); ASSERT(!m_versionChangeTransaction || m_versionChangeTransaction->isVersionChange()); if (!m_versionChangeTransaction) { ec.code = IDBDatabaseException::InvalidStateError; ec.message = ASCIILiteral("Failed to execute 'createObjectStore' on 'IDBDatabase': The database is not running a version change transaction."); return nullptr; } if (!m_versionChangeTransaction->isActive()) { ec.code = IDBDatabaseException::TransactionInactiveError; return nullptr; } if (m_info.hasObjectStore(name)) { ec.code = IDBDatabaseException::ConstraintError; ec.message = ASCIILiteral("Failed to execute 'createObjectStore' on 'IDBDatabase': An object store with the specified name already exists."); return nullptr; } if (!keyPath.isNull() && !keyPath.isValid()) { ec.code = IDBDatabaseException::SyntaxError; ec.message = ASCIILiteral("Failed to execute 'createObjectStore' on 'IDBDatabase': The keyPath option is not a valid key path."); return nullptr; } if (autoIncrement && !keyPath.isNull()) { if ((keyPath.type() == IDBKeyPath::Type::String && keyPath.string().isEmpty()) || keyPath.type() == IDBKeyPath::Type::Array) { ec.code = IDBDatabaseException::InvalidAccessError; ec.message = ASCIILiteral("Failed to execute 'createObjectStore' on 'IDBDatabase': The autoIncrement option was set but the keyPath option was empty or an array."); return nullptr; } } // Install the new ObjectStore into the connection's metadata. IDBObjectStoreInfo info = m_info.createNewObjectStore(name, keyPath, autoIncrement); // Create the actual IDBObjectStore from the transaction, which also schedules the operation server side. Ref<IDBObjectStore> objectStore = m_versionChangeTransaction->createObjectStore(info); return adoptRef(&objectStore.leakRef()); }
PassRefPtr<IDBObjectStore> IDBDatabase::createObjectStore(const String& name, const IDBKeyPath& keyPath, bool autoIncrement, ExceptionState& exceptionState) { IDB_TRACE("IDBDatabase::createObjectStore"); blink::Platform::current()->histogramEnumeration("WebCore.IndexedDB.FrontEndAPICalls", IDBCreateObjectStoreCall, IDBMethodsMax); if (!m_versionChangeTransaction) { exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVersionChangeTransactionErrorMessage); return nullptr; } if (m_versionChangeTransaction->isFinished()) { exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); return nullptr; } if (!m_versionChangeTransaction->isActive()) { exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); return nullptr; } if (containsObjectStore(name)) { exceptionState.throwDOMException(ConstraintError, "An object store with the specified name already exists."); return nullptr; } if (!keyPath.isNull() && !keyPath.isValid()) { exceptionState.throwDOMException(SyntaxError, "The keyPath option is not a valid key path."); return nullptr; } if (autoIncrement && ((keyPath.type() == IDBKeyPath::StringType && keyPath.string().isEmpty()) || keyPath.type() == IDBKeyPath::ArrayType)) { exceptionState.throwDOMException(InvalidAccessError, "The autoIncrement option was set but the keyPath option was empty or an array."); return nullptr; } int64_t objectStoreId = m_metadata.maxObjectStoreId + 1; m_backend->createObjectStore(m_versionChangeTransaction->id(), objectStoreId, name, keyPath, autoIncrement); IDBObjectStoreMetadata metadata(name, objectStoreId, keyPath, autoIncrement, WebIDBDatabase::minimumIndexId); RefPtr<IDBObjectStore> objectStore = IDBObjectStore::create(metadata, m_versionChangeTransaction.get()); m_metadata.objectStores.set(metadata.id, metadata); ++m_metadata.maxObjectStoreId; m_versionChangeTransaction->objectStoreCreated(name, objectStore); return objectStore.release(); }
RefPtr<WebCore::IDBObjectStore> IDBDatabase::createObjectStore(const String& name, const IDBKeyPath& keyPath, bool autoIncrement, ExceptionCode& ec) { LOG(IndexedDB, "IDBDatabase::createObjectStore"); ASSERT(!m_versionChangeTransaction || m_versionChangeTransaction->isVersionChange()); if (!m_versionChangeTransaction) { ec = IDBDatabaseException::InvalidStateError; return nullptr; } if (!m_versionChangeTransaction->isActive()) { ec = IDBDatabaseException::TransactionInactiveError; return nullptr; } if (m_info.hasObjectStore(name)) { ec = IDBDatabaseException::ConstraintError; return nullptr; } if (!keyPath.isNull() && !keyPath.isValid()) { ec = IDBDatabaseException::SyntaxError; return nullptr; } if (autoIncrement && !keyPath.isNull()) { if ((keyPath.type() == IndexedDB::KeyPathType::String && keyPath.string().isEmpty()) || keyPath.type() == IndexedDB::KeyPathType::Array) { ec = IDBDatabaseException::InvalidAccessError; return nullptr; } } // Install the new ObjectStore into the connection's metadata. IDBObjectStoreInfo info = m_info.createNewObjectStore(name, keyPath, autoIncrement); // Create the actual IDBObjectStore from the transaction, which also schedules the operation server side. Ref<IDBObjectStore> objectStore = m_versionChangeTransaction->createObjectStore(info); return adoptRef(&objectStore.leakRef()); }
PassRefPtr<IDBObjectStore> IDBDatabase::createObjectStore(const String& name, const IDBKeyPath& keyPath, bool autoIncrement, ExceptionCode& ec) { IDB_TRACE("IDBDatabase::createObjectStore"); HistogramSupport::histogramEnumeration("WebCore.IndexedDB.FrontEndAPICalls", IDBCreateObjectStoreCall, IDBMethodsMax); if (!m_versionChangeTransaction) { ec = IDBDatabaseException::InvalidStateError; return 0; } if (!m_versionChangeTransaction->isActive()) { ec = IDBDatabaseException::TransactionInactiveError; return 0; } if (containsObjectStore(name)) { ec = IDBDatabaseException::ConstraintError; return 0; } if (!keyPath.isNull() && !keyPath.isValid()) { ec = IDBDatabaseException::SyntaxError; return 0; } if (autoIncrement && ((keyPath.type() == IDBKeyPath::StringType && keyPath.string().isEmpty()) || keyPath.type() == IDBKeyPath::ArrayType)) { ec = IDBDatabaseException::InvalidAccessError; return 0; } int64_t objectStoreId = m_metadata.maxObjectStoreId + 1; m_backend->createObjectStore(m_versionChangeTransaction->id(), objectStoreId, name, keyPath, autoIncrement); IDBObjectStoreMetadata metadata(name, objectStoreId, keyPath, autoIncrement, IDBDatabaseBackendInterface::MinimumIndexId); RefPtr<IDBObjectStore> objectStore = IDBObjectStore::create(metadata, m_versionChangeTransaction.get()); m_metadata.objectStores.set(metadata.id, metadata); ++m_metadata.maxObjectStoreId; m_versionChangeTransaction->objectStoreCreated(name, objectStore); return objectStore.release(); }
RefPtr<IDBObjectStore> LegacyDatabase::createObjectStore(const String& name, const IDBKeyPath& keyPath, bool autoIncrement, ExceptionCode& ec) { LOG(StorageAPI, "LegacyDatabase::createObjectStore"); if (!m_versionChangeTransaction) { ec = IDBDatabaseException::InvalidStateError; return 0; } if (!m_versionChangeTransaction->isActive()) { ec = IDBDatabaseException::TransactionInactiveError; return 0; } if (containsObjectStore(name)) { ec = IDBDatabaseException::ConstraintError; return 0; } if (!keyPath.isNull() && !keyPath.isValid()) { ec = IDBDatabaseException::SyntaxError; return 0; } if (autoIncrement && ((keyPath.type() == IDBKeyPath::StringType && keyPath.string().isEmpty()) || keyPath.type() == IDBKeyPath::ArrayType)) { ec = IDBDatabaseException::InvalidAccessError; return 0; } int64_t objectStoreId = m_metadata.maxObjectStoreId + 1; m_backend->createObjectStore(m_versionChangeTransaction->id(), objectStoreId, name, keyPath, autoIncrement); IDBObjectStoreMetadata metadata(name, objectStoreId, keyPath, autoIncrement, IDBDatabaseBackend::MinimumIndexId); RefPtr<LegacyObjectStore> objectStore = LegacyObjectStore::create(metadata, m_versionChangeTransaction.get()); m_metadata.objectStores.set(metadata.id, metadata); ++m_metadata.maxObjectStoreId; m_versionChangeTransaction->objectStoreCreated(name, objectStore); return objectStore.release(); }