backend/schema/catalog/schema.h (200 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_SCHEMA_H_ #define THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_SCHEMA_CATALOG_SCHEMA_H_ #include <cstdint> #include <memory> #include <string> #include <utility> #include <vector> #include "google/spanner/admin/database/v1/common.pb.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" #include "backend/common/case.h" #include "backend/schema/catalog/change_stream.h" #include "backend/schema/catalog/database_options.h" #include "backend/schema/catalog/index.h" #include "backend/schema/catalog/locality_group.h" #include "backend/schema/catalog/model.h" #include "backend/schema/catalog/named_schema.h" #include "backend/schema/catalog/placement.h" #include "backend/schema/catalog/property_graph.h" #include "backend/schema/catalog/proto_bundle.h" #include "backend/schema/catalog/sequence.h" #include "backend/schema/catalog/table.h" #include "backend/schema/catalog/udf.h" #include "backend/schema/catalog/view.h" #include "backend/schema/graph/schema_graph.h" #include "common/constants.h" namespace google { namespace spanner { namespace emulator { namespace backend { namespace database_api = ::google::spanner::admin::database::v1; // Schema represents a single generation of schema of a database. It is an // abstract class that provides a convenient interface for looking up schema // objects. A Schema doesn't take ownership of the schema objects. That is // managed by the SchemaGraph passed to it and which must outlive the // Schema instance. class Schema { public: Schema() : graph_(SchemaGraph::CreateEmpty()), proto_bundle_(ProtoBundle::CreateEmpty()), dialect_(database_api::DatabaseDialect::GOOGLE_STANDARD_SQL), // Only populated for PostgreSQL databases (mirrors production) database_id_("") {} explicit Schema(const SchemaGraph* graph, std::shared_ptr<const ProtoBundle> proto_bundle, const database_api::DatabaseDialect& dialect, std::string_view database_id); virtual ~Schema() = default; // Returns the generation number of this schema. int64_t generation() const { return generation_; } // Dumps the schema to ddl::DDLStatementList. ddl::DDLStatementList Dump() const; // Finds a view by its name. Returns a const pointer of the view, or // nullptr if the view is not found. Name comparison is case-insensitive. const View* FindView(const std::string& view_name) const; // Same as FindView but case-sensitive. const View* FindViewCaseSensitive(const std::string& view_name) const; // Finds a UDF by its name. Returns a const pointer of the UDF, or // nullptr if the UDF is not found. Name comparison is case-insensitive. const Udf* FindUdf(const std::string& udf_name) const; // Same as FindUdf but case-sensitive. const Udf* FindUdfCaseSensitive(const std::string& udf_name) const; // Finds a table by its name or synonym. Returns a const pointer of the table, // or nullptr if the table is not found. Name comparison is case-insensitive. const Table* FindTable(const std::string& table_name) const; // Finds a table by its synonym. Returns a const pointer of the table, or // nullptr if a table using the synonym is not found. Name comparison is // case-insensitive. const Table* FindTableUsingSynonym(const std::string& table_synonym) const; // Same as FindTable but case-sensitive. const Table* FindTableCaseSensitive(const std::string& table_name) const; // Same as FindTableUsingSynonym but case-sensitive. const Table* FindTableUsingSynonymCaseSensitive( const std::string& table_synonym) const; // Finds an index by its name. Returns a const pointer of the index, or // nullptr if the index is not found. Name comparison is case-insensitive. const Index* FindIndex(const std::string& index_name) const; // Same as FindIndex but case-sensitive. const Index* FindIndexCaseSensitive(const std::string& index_name) const; // Finds all indexes with the given name. std::vector<const Index*> FindIndexesUnderName( const std::string& index_name) const; // Finds a change stream by its name. Returns a const pointer of the // change stream, or nullptr if the change stream is not found. Name // comparison is case-insensitive. const ChangeStream* FindChangeStream( const std::string& change_stream_name) const; // Finds a Placement by its name. Returns a const pointer of the // change stream, or nullptr if the placement is not found. Name // comparison is case-insensitive. const Placement* FindPlacement(const std::string& placement_name) const; // Finds a sequence by its name. Returns a const pointer of the sequence, or // a nullptr if the sequence is not found. Name comparison is // case-insensitive. If exclude_internal is true, internal sequences are // excluded from the search. const Sequence* FindSequence(const std::string& sequence_name, bool exclude_internal = false) const; // Finds a model by its name. Returns a const pointer of the model, // or nullptr if the change stream is not found. Name comparison is // case-insensitive. const Model* FindModel(const std::string& model_name) const; // Finds a property graph by its name. Returns a const pointer of the // property graph, or nullptr if the property graph is not found. Name // comparison is case-insensitive. const PropertyGraph* FindPropertyGraph(const std::string& graph_name) const; // Finds a named schema by its name. Returns a const pointer of the named // schema, or a nullptr if the named schema is not found. Name comparison is // case-insensitive. const NamedSchema* FindNamedSchema( const std::string& named_schema_name) const; // Finds a locality group by its name. Returns a const pointer of the locality // group, or a nullptr if the locality group is not found. Name comparison is // case-insensitive. const LocalityGroup* FindLocalityGroup( const std::string& locality_group_name) const; // List all the user-visible tables in this schema. absl::Span<const Table* const> tables() const { return tables_; } // List all the user-visible synonyms in this schema. absl::Span<const std::string> synonyms() const { return synonyms_; } absl::Span<const View* const> views() const { return views_; } // List all the user-visible UDFs in this schema. absl::Span<const Udf* const> udfs() const { return udfs_; } // List all the user-visible change streams in this schema. absl::Span<const ChangeStream* const> change_streams() const { return change_streams_; } // List all user-visible and internal sequences in this schema. absl::Span<const Sequence* const> sequences() const { return sequences_; } // List all the user-visible sequences in this schema. std::vector<const Sequence*> user_visible_sequences() const { std::vector<const Sequence*> user_sequences; for (const Sequence* sequence : sequences_) { if (!sequence->is_internal_use()) { user_sequences.push_back(sequence); } } return user_sequences; } // List all the user-visible models in this schema. absl::Span<const Model* const> models() const { return models_; } // List all the user-visible property graphs in this schema. absl::Span<const PropertyGraph* const> property_graphs() const { return property_graphs_; } // List all the user-visible named schemas in this schema. absl::Span<const NamedSchema* const> named_schemas() const { return named_schemas_; } // List all the locality groups in this schema. absl::Span<const LocalityGroup* const> locality_groups() const { return locality_groups_; } // Returns the default time zone for this schema. std::string default_time_zone() const { if (options() != nullptr && options()->default_time_zone().has_value()) { return options()->default_time_zone().value(); } return kDefaultTimeZone; } // Return user-visible options in this schema. const DatabaseOptions* const options() const { return database_options_; } // Return the underlying SchemaGraph owning the objects in the schema. const SchemaGraph* GetSchemaGraph() const { return graph_; } // Returns the number of indices in the schema. int num_index() const { return index_map_.size(); } // Returns the number of change streams in the schema. int num_change_stream() const { return change_streams_map_.size(); } // Returns the number of sequences in the schema. int num_sequence() const { return sequences_map_.size(); } // Returns the number of named schemas in the schema. int num_named_schema() const { return named_schemas_map_.size(); } // Returns the number of table synonyms in the schema. int num_table_synonym() const { return synonyms_map_.size(); } // Returns the number of locality groups in the schema. int num_locality_groups() const { return locality_groups_map_.size(); } absl::Span<const Placement* const> placements() const { return placements_; } // Returns the shared pointer to the ProtoBundle holding the proto types. std::shared_ptr<const ProtoBundle> proto_bundle() const { return proto_bundle_; } // Returns the database dialect. database_api::DatabaseDialect dialect() const { return dialect_; } // Returns the database id. std::string_view database_id() const { return database_id_; } std::vector<const Index*> vector_indexes() const { std::vector<const Index*> vector_indexes; for (const auto& [name, index] : index_map_) { if (index->is_vector_index()) { vector_indexes.push_back(index); } } return vector_indexes; } private: // Tries to find the managed index from the non-fingerprint part of the // index name. const Index* FindManagedIndex(const std::string& index_name) const; // Manages the lifetime of all schema objects. Maintains the order // in which the nodes were added to the graph. Must outlive *this. const SchemaGraph* graph_; // The generation number of this schema. int64_t generation_ = 0; // A vector that maintains the original order of tables in the DDL. std::vector<const Table*> tables_; // A map that owns all the views. Key is the name of the view. Hash and // comparison on the keys are case-insensitive. CaseInsensitiveStringMap<const View*> views_map_; // A vector that maintains the original order of views in the DDL. std::vector<const View*> views_; // A map that owns all the UDFs. Key is the name of the UDF. Hash and // comparison on the keys are case-insensitive. CaseInsensitiveStringMap<const Udf*> udfs_map_; // A vector that maintains the original order of UDFs in the DDL. std::vector<const Udf*> udfs_; // A map that owns all the tables. Key is the name of the tables. Hash and // comparison on the keys are case-insensitive. CaseInsensitiveStringMap<const Table*> tables_map_; // A map for synonyms to target tables. Hash and comparison on the keys are // case-insensitive. CaseInsensitiveStringMap<const Table*> synonyms_map_; // A vector that lists table synonyms in the DDL for quicker retrieval of // the synonym list. std::vector<std::string> synonyms_; // A vector that maintains the original order of change streams in the DDL. std::vector<const ChangeStream*> change_streams_; // A map that owns all the change streams. Key is the name of the change // stream. Hash and comparison on the keys are case-insensitive. CaseInsensitiveStringMap<const ChangeStream*> change_streams_map_; // A vector that maintains the original order of placements in the DDL. std::vector<const Placement*> placements_; // A map that owns all the placements. Key is the name of the placement. Hash // and comparison on the keys are case-insensitive. CaseInsensitiveStringMap<const Placement*> placements_map_; // A vector that maintains the original order of models in the DDL. std::vector<const Model*> models_; // A map that owns all the models. Key is the name of the model. // Hash and comparison on the keys are case-insensitive. CaseInsensitiveStringMap<const Model*> models_map_; // A map that owns all of the indexes. Key is the name of the index. Hash and // comparison on the keys are case-insensitive. CaseInsensitiveStringMap<const Index*> index_map_; // Holds the proto type information for this schema. This is a shared pointer // to prevent creating multiple copies of the ProtoBundle for every schema // update even though there is no type change. const std::shared_ptr<const ProtoBundle> proto_bundle_; // A vector that maintains the original order of sequences in the DDL. std::vector<const Sequence*> sequences_; // A map that owns all the sequences. Key is the name of the sequence. Hash // and comparison on the keys are case-insensitive. CaseInsensitiveStringMap<const Sequence*> sequences_map_; // A vector that maintains the original order of named schemas in the DDL. std::vector<const NamedSchema*> named_schemas_; // A map that owns all the named schemas. Key is the name of the named // schemas. Hash and comparison on the keys are case-insensitive. CaseInsensitiveStringMap<const NamedSchema*> named_schemas_map_; // A vector that maintains the original order of locality groups in the DDL. std::vector<const LocalityGroup*> locality_groups_; // A map that owns all the locality groups. Key is the name of the locality // group. Hash and comparison on the keys are case-insensitive. CaseInsensitiveStringMap<const LocalityGroup*> locality_groups_map_; // A vector that maintains the original order of property graphs in the DDL. std::vector<const PropertyGraph*> property_graphs_; // A map that owns all the property graphs. Key is the name of the property // graph. Hash and comparison on the keys are case-insensitive. CaseInsensitiveStringMap<const PropertyGraph*> property_graphs_map_; // Database options in the DDL. const DatabaseOptions* database_options_ = nullptr; // Holds the database dialect for this schema. const database_api::DatabaseDialect dialect_; // Holds the database id for this schema. const std::string database_id_; }; // A Schema that also owns the SchemaGraph that manages the lifetime of the // schema nodes. class OwningSchema : public Schema { public: explicit OwningSchema( std::unique_ptr<const SchemaGraph> graph, std::shared_ptr<const ProtoBundle> proto_bundle, const database_api::DatabaseDialect& dialect, // TODO: b/395063354 - Remove default value once spangres is migrated std::string_view database_id = "") : Schema(graph.get(), proto_bundle, dialect, database_id), graph_(std::move(graph)) {} explicit OwningSchema( std::unique_ptr<const SchemaGraph> graph, const database_api::DatabaseDialect& dialect, // TODO: b/395063354 - Remove default value once spangres is migrated std::string_view database_id = "") : Schema(graph.get(), google::spanner::emulator::backend::ProtoBundle::CreateEmpty(), dialect, database_id), graph_(std::move(graph)) {} ~OwningSchema() override = default; private: std::unique_ptr<const SchemaGraph> graph_; }; class SDLObjectName { public: // Split a name into the "schema" part and the "in-schema local name" part. // "A.B" -> <"A", "B">. Nested schemas are retained in the "schema" part. // For example, "A.B.C" -> <"A.B", "C">. static std::pair<absl::string_view, absl::string_view> SplitSchemaName( absl::string_view name); static absl::string_view GetSchemaName(absl::string_view name) { return SplitSchemaName(name).first; } static absl::string_view GetInSchemaName(absl::string_view name) { return SplitSchemaName(name).second; } static bool IsFullyQualifiedName(absl::string_view name) { return !GetSchemaName(name).empty(); } static bool InSameSchema(absl::string_view name1, absl::string_view name2) { return GetSchemaName(name1) == GetSchemaName(name2); } }; } // namespace backend } // namespace emulator } // namespace spanner } // namespace google #endif // THIRD_PARTY_CLOUD_SPANNER_EMULATOR_BACKEND_SCHEMA_CATALOG_SCHEMA_H_