backend/schema/catalog/table.h (168 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_TABLE_H_
#define THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_SCHEMA_CATALOG_TABLE_H_
#include <cstdint>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/strings/substitute.h"
#include "absl/types/span.h"
#include "backend/common/case.h"
#include "backend/common/ids.h"
#include "backend/schema/catalog/change_stream.h"
#include "backend/schema/catalog/check_constraint.h"
#include "backend/schema/catalog/column.h"
#include "backend/schema/catalog/index.h"
#include "backend/schema/catalog/locality_group.h"
#include "backend/schema/ddl/operations.pb.h"
#include "backend/schema/graph/schema_graph_editor.h"
#include "backend/schema/graph/schema_node.h"
namespace google {
namespace spanner {
namespace emulator {
namespace backend {
class ForeignKey;
class Index;
class ChangeStream;
// Table represents a table in a database.
class Table : public SchemaNode {
public:
// Describes what action to take when the row from the parent table is
// deleted.
enum class OnDeleteAction {
// Ensures that no child rows exist.
kNoAction,
// Delete the child rows of the parent row.
kCascade
};
// Returns the name of the table.
std::string Name() const { return name_; }
// Returns the unique ID of this table.
const TableID id() const { return id_; }
// Returns the child tables of this table.
absl::Span<const Table* const> children() const { return child_tables_; }
// Returns the parent table of this table, or nullptr if this table does not
// have a parent table.
const Table* parent() const { return parent_table_; }
// Returns the Change Stream that owns this table if one exists.
const ChangeStream* owner_change_stream() const {
return owner_change_stream_;
}
// Returns the locality group this column belongs to.
const LocalityGroup* locality_group() const { return locality_group_; }
// Returns the Index that owns this table, or nullptr if this table is not
// owned by an Index.
const Index* owner_index() const { return owner_index_; }
// Returns the on delete action of this table.
OnDeleteAction on_delete_action() const {
return on_delete_action_.value_or(OnDeleteAction::kNoAction);
}
// Returns the row deletion policy of this table.
std::optional<ddl::RowDeletionPolicy> row_deletion_policy() const {
return row_deletion_policy_;
}
// Returns the list of all columns of this table.
absl::Span<const Column* const> columns() const { return columns_; }
// Returns the list of all foreign keys of this table.
absl::Span<const ForeignKey* const> foreign_keys() const {
return foreign_keys_;
}
// Returns the list of all check constraints of this table.
absl::Span<const CheckConstraint* const> check_constraints() const {
return check_constraints_;
}
// Returns the list of all foreign keys that are referencing this table.
absl::Span<const ForeignKey* const> referencing_foreign_keys() const {
return referencing_foreign_keys_;
}
// Returns the list of all indexes on this table.
absl::Span<const Index* const> indexes() const { return indexes_; }
// Returns the list of change streams tracking this entire table (explicitly
// by table name or implicitly by ALL).
absl::Span<const ChangeStream* const> change_streams() const {
return change_streams_;
}
// Returns the list of all change streams explicitly tracking this table by
// the table name.
absl::Span<const ChangeStream* const>
change_streams_explicitly_tracking_table() const {
return change_streams_explicitly_tracking_table_;
}
bool is_trackable_by_change_stream() const { return is_public(); }
std::vector<std::string> trackable_columns() const {
std::vector<std::string> trackable_columns;
for (const Column* column : columns_) {
if (column->is_trackable_by_change_stream()) {
trackable_columns.push_back(column->Name());
}
}
return trackable_columns;
}
// Returns the primary key of this table.
const absl::Span<const KeyColumn* const> primary_key() const {
return primary_key_;
}
// Returns true if the Table is publicly visible, i.e. can be accessed
// directly by a user request.
bool is_public() const {
return owner_change_stream_ == nullptr && owner_index_ == nullptr;
}
std::optional<uint32_t> interleave_in_parent_postgresql_oid() const {
return interleave_in_parent_postgresql_oid_;
}
void set_interleave_in_parent_postgresql_oid(uint32_t oid) {
interleave_in_parent_postgresql_oid_ = oid;
}
std::optional<uint32_t> primary_key_index_postgresql_oid() const {
return primary_key_index_postgresql_oid_;
}
void set_primary_key_index_postgresql_oid(uint32_t oid) {
primary_key_index_postgresql_oid_ = oid;
}
// Returns the synonym of this table.
const std::string& synonym() const { return synonym_; }
// Finds a column by its name. Returns a const pointer to the column, or
// nullptr if the column is not found. Name comparison is case-insensitive.
const Column* FindColumn(const std::string& column_name) const;
// Finds an index on the table by its name. Name comparison is
// case-insensitive.
const Index* FindIndex(const std::string& index_name) const;
// Finds an indexes fully qualified name given a name (qualified or not).
std::string FindIndexQualifiedName(
const std::string& qualified_or_unqualified_name) const;
// Finds a change stream on the table by its name. Name comparison is
// case-insensitive.
const ChangeStream* FindChangeStream(
const std::string& change_stream_name) const;
// Same as above, but name comparison is case-sensitive.
const Column* FindColumnCaseSensitive(const std::string& column_name) const;
// Finds a KeyColumn by name. Returns nullptr if table doesn't contain
// a column named `column_name` or if it's not a key column.
const KeyColumn* FindKeyColumn(const std::string& column_name) const;
// Returns the check constraint with a given constraint name. Returns nullptr
// if not found.
const CheckConstraint* FindCheckConstraint(
const std::string& constraint_name) const;
// Returns the foreign key with a given constraint name. Returns nullptr if
// not found.
const ForeignKey* FindForeignKey(const std::string& constraint_name) const;
// Returns the foreign key with a given constraint name that references this
// table. Returns nullptr if not found.
const ForeignKey* FindReferencingForeignKey(
const std::string& constraint_name) const;
// Prints a debug string for the primary key in the following format:
// <key_col1>, <key_col2>, ..., <key_coln>
std::string PrimaryKeyDebugString() const;
// SchemaNode interface implementation.
// ------------------------------------
std::optional<SchemaNameInfo> GetSchemaNameInfo() const override {
return SchemaNameInfo{.name = name_, .kind = "Table", .global = true};
}
absl::Status Validate(SchemaValidationContext* context) const override;
absl::Status ValidateUpdate(const SchemaNode* orig,
SchemaValidationContext* context) const override;
std::string DebugString() const override {
return absl::Substitute("T:$0[$1]", Name(), id_);
}
class Builder;
class Editor;
private:
friend class TableValidator;
using ValidationFn =
std::function<absl::Status(const Table*, SchemaValidationContext*)>;
using UpdateValidationFn = std::function<absl::Status(
const Table*, const Table*, SchemaValidationContext*)>;
// Constructors are private and only friend classes are able to build /
// modify.
Table(const ValidationFn& validate, const UpdateValidationFn& validate_update)
: validate_(validate), validate_update_(validate_update) {}
Table(const Table&) = default;
std::unique_ptr<SchemaNode> ShallowClone() const override {
auto clone = absl::WrapUnique(new Table(*this));
return clone;
}
absl::Status DeepClone(SchemaGraphEditor* editor,
const SchemaNode* orig) override;
// Validation delegates.
const ValidationFn validate_;
const UpdateValidationFn validate_update_;
// The name of this table.
std::string name_;
// A unique ID for identifying this table in the schema that owns this table.
TableID id_;
// List of table columns, in the same order as found in the corresponding DDL.
std::vector<const Column*> columns_;
// List of check constraints defined on this table, in the same order as found
// in the corresponding DDL.
std::vector<const CheckConstraint*> check_constraints_;
// List of foreign keys defined on this table, in the same order as found in
// the corresponding DDL.
std::vector<const ForeignKey*> foreign_keys_;
// List of foreign keys referencing this table, in the same order as added in
// the corresponding DDL.
std::vector<const ForeignKey*> referencing_foreign_keys_;
// List of indexes referring to this table. These are owned by the Schema, not
// by the Table.
std::vector<const Index*> indexes_;
// List of change streams tracking this entire table (explicitly by table name
// or implicitly by ALL). These are owned by the Schema, not by the Table.
std::vector<const ChangeStream*> change_streams_;
// List of change streams explicitly tracking this table by the table name.
// These are owned by the Schema, not by the Table.
std::vector<const ChangeStream*> change_streams_explicitly_tracking_table_;
// The Change Stream that owns this table if one exists.
const ChangeStream* owner_change_stream_ = nullptr;
// The Index that owns this table if one exists. This attribute is null for
// all but index data tables.
const Index* owner_index_ = nullptr;
// A map of case-insensitive column names to their backend::Column* pointers.
CaseInsensitiveStringMap<const Column*> columns_map_;
// primary_key_ defines the primary key columns of a table. Order of the
// elements in the vector is the same as the order in which they are listed
// in the PRIMARY KEY clause.
// If 'this' represents the data table for an index, then primary_key_
// consists of the owning index's key columns, followed by the indexed table's
// key columns (excluding the columns already specified in the index key)
// in the order defined in their respective CREATE INDEX ON and PRIMARY KEY
// clauses.
std::vector<const KeyColumn*> primary_key_;
// Child tables that are interleaved in this table.
std::vector<const Table*> child_tables_;
// Parent table of this table. If null, this table is a top level table.
const Table* parent_table_ = nullptr;
// Action to take for a child row in 'this' table if a row from the parent
// table is deleted. Set to nullopt if no action was specified by the user
// in the CREATE TABLE statement.
std::optional<OnDeleteAction> on_delete_action_ = std::nullopt;
// Row deletion policy of this table. Set to nullopt if not specified.
std::optional<ddl::RowDeletionPolicy> row_deletion_policy_ = std::nullopt;
// Synonym.
std::string synonym_;
// Additional PG oids.
std::optional<uint32_t> interleave_in_parent_postgresql_oid_ = std::nullopt;
std::optional<uint32_t> primary_key_index_postgresql_oid_ = std::nullopt;
// The locality group this table belongs to.
const LocalityGroup* locality_group_ = nullptr;
};
// Returns the name of the schema declared owning object (index or table) of
// 'table'. Used to generate proper error messages.
std::string OwningObjectName(const Table* table);
// Returns the kind of object ("Index" or "Table") which is the owner of
// 'table'. Used to generate proper error messages.
std::string OwningObjectType(const Table* table);
} // namespace backend
} // namespace emulator
} // namespace spanner
} // namespace google
#endif // THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_SCHEMA_CATALOG_TABLE_H_