backend/schema/catalog/index.h (104 lines of code) (raw):
//
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_SCHEMA_CATALOG_INDEX_H_
#define THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_SCHEMA_CATALOG_INDEX_H_
#include <algorithm>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/types/span.h"
#include "backend/schema/catalog/column.h"
#include "backend/schema/catalog/locality_group.h"
#include "backend/schema/catalog/table.h"
#include "backend/schema/graph/schema_node.h"
namespace google {
namespace spanner {
namespace emulator {
namespace backend {
// Index represents a secondary index on a table.
//
// The index stores pointers to the indexed table as well as the backing data
// table which stores the index information (index columns + indexed table
// primary key columns + storing columns). The primary key of the backing data
// table will be the primary key of the indexed table prefixed by the index
// columns (with duplicate columns removed) to guarantee uniqueness of the data
// table key.
//
// Example:
//
// CREATE TABLE Albums (
// SingerId INT64 NOT NULL,
// AlbumId INT64 NOT NULL,
// AlbumTitle STRING(MAX),
// ReleaseDate DATE
// ) PRIMARY KEY (SingerId, AlbumId),
// INTERLEAVE IN PARENT Singers ON DELETE CASCADE;
//
// CREATE INDEX AlbumsByAlbumTitle ON Albums(AlbumTitle);
//
// This will create an index 'AlbumsByAlbumTitle' on the table 'Albums'. The
// index data table will store the column 'AlbumTitle' which is the index
// column, followed by 'SingerId', 'AlbumId' which are the primary key columns
// of indexed table. If any storing columns were present they would be appended
// to the end.
//
class Index : public SchemaNode {
public:
// Returns the name of this index.
std::string Name() const { return name_; }
// Returns the table that is indexed.
const Table* indexed_table() const { return indexed_table_; }
// Returns the backing table which stores the index data.
const Table* index_data_table() const { return index_data_table_; }
// Returns the parent table that the index data table is interleaved in, if
// one exists.
const Table* parent() const;
// Returns the key columns of the index as declared in the CREATE INDEX
// statement.
absl::Span<const KeyColumn* const> key_columns() const {
return key_columns_;
}
// Returns the list of all the storing columns.
absl::Span<const Column* const> stored_columns() const {
return stored_columns_;
}
// Returns the list of all the null filtered columns.
absl::Span<const Column* const> null_filtered_columns() const {
return null_filtered_columns_;
}
bool is_null_filtered_column(const Column* column) const {
auto it = std::find(null_filtered_columns_.begin(),
null_filtered_columns_.end(), column);
return it != null_filtered_columns_.end();
}
// Returns true if this is a unique index.
bool is_unique() const { return is_unique_; }
// Returns true if this index has NULL_FILTERED enabled.
bool is_null_filtered() const { return is_null_filtered_; }
// Returns true if this index is managed by other schema nodes. Managed
// indexes are regular indexes except for their lifecycles. Users cannot
// create, alter or drop managed indexes.
bool is_managed() const { return !managing_nodes_.empty(); }
// Returns the nodes that are managing this index.
absl::Span<const SchemaNode* const> managing_nodes() const {
return managing_nodes_;
}
// Returns the type of the index.
bool is_search_index() const {
return index_type_ == IndexType::kSearchIndex;
}
bool is_vector_index() const {
return index_type_ == IndexType::kVectorIndex;
}
// Returns the list of partition by column defined in the search index.
absl::Span<const Column* const> partition_by() const { return partition_by_; }
// Returns the list of order by column defined in the search index.
absl::Span<const Column* const> order_by() const { return order_by_; }
// Returns a detailed string which lists information about this index.
std::string FullDebugString() const;
// Returns the locality group this index belongs to.
const LocalityGroup* locality_group() const { return locality_group_; }
// SchemaNode interface implementation.
// ------------------------------------
ddl::VectorIndexOptionsProto vector_index_options() const {
return vector_index_options_;
}
std::optional<SchemaNameInfo> GetSchemaNameInfo() const override {
return SchemaNameInfo{.name = name_, .kind = "Index", .global = true};
}
absl::Status Validate(SchemaValidationContext* context) const override;
absl::Status ValidateUpdate(const SchemaNode* old,
SchemaValidationContext* context) const override;
std::string DebugString() const override;
class Builder;
class Editor;
private:
friend class IndexValidator;
using ValidationFn =
std::function<absl::Status(const Index*, SchemaValidationContext*)>;
using UpdateValidationFn = std::function<absl::Status(
const Index*, const Index*, SchemaValidationContext*)>;
// Constructors are private and only friend classes are able to build /
// modify.
Index(const ValidationFn& validate, const UpdateValidationFn& validate_update)
: validate_(validate), validate_update_(validate_update) {}
Index(const Index&) = default;
std::unique_ptr<SchemaNode> ShallowClone() const override {
return absl::WrapUnique(new Index(*this));
}
absl::Status DeepClone(SchemaGraphEditor* editor,
const SchemaNode* orig) override;
// Validation delegates.
const ValidationFn validate_;
const UpdateValidationFn validate_update_;
// The name of this index.
std::string name_;
// The table that this index references.
const Table* indexed_table_;
// The backing table that stores the index data.
const Table* index_data_table_;
// The columns declared as the index's key, in the same order
// as they appear in the CREATE INDEX statement. References are
// to the corresponding KeyColumn(s) in 'index_data_table_'.
std::vector<const KeyColumn*> key_columns_;
// Additional columns specified in the 'STORING' clause in the same
// order as they appear in the CREATE INDEX statement. References are
// to the corresponding columns in 'index_data_table_'.
std::vector<const Column*> stored_columns_;
// Nodes that are managing this index. The first node creates the index and
// adds itself as a managing node. Subsequent nodes that can share this index
// add themselves as a managing node rather than creating a new index. Dropped
// nodes remove themselves. The last node dropped also drops this index.
std::vector<const SchemaNode*> managing_nodes_;
// Whether the indexed columns form a unique key. If true, additional
// constraints will be checked to enforce uniqueness for the Index.
bool is_unique_ = false;
// Whether this index has NULL_FILTERED enabled which applies to all index key
// columns.
bool is_null_filtered_ = false;
// Columns specified in the WHERE IS NOT NULL clause. References are
// to the corresponding columns in 'index_data_table_'.
std::vector<const Column*> null_filtered_columns_;
// The type of the index.
enum class IndexType { kIndex, kSearchIndex, kVectorIndex };
IndexType index_type_ = IndexType::kIndex;
// Currently applies only to search index. A list of key parts that the index
// is partitioned by. If this is empty, then the index is not partitioned.
std::vector<const Column*> partition_by_;
// Currently applies only to search index. A list of key parts that the index
// is ordered by. If this is empty, then the index is unordered.
std::vector<const Column*> order_by_;
// Applies only to vector index. The options for the vector index.
ddl::VectorIndexOptionsProto vector_index_options_;
// The locality group this index belongs to.
const LocalityGroup* locality_group_ = nullptr;
};
} // namespace backend
} // namespace emulator
} // namespace spanner
} // namespace google
#endif // THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_SCHEMA_CATALOG_INDEX_H_