diff options
Diffstat (limited to 'lib/gitlab/database/gitlab_schema.rb')
-rw-r--r-- | lib/gitlab/database/gitlab_schema.rb | 85 |
1 files changed, 41 insertions, 44 deletions
diff --git a/lib/gitlab/database/gitlab_schema.rb b/lib/gitlab/database/gitlab_schema.rb index 4394c089b22..9b58284b389 100644 --- a/lib/gitlab/database/gitlab_schema.rb +++ b/lib/gitlab/database/gitlab_schema.rb @@ -3,13 +3,15 @@ # This module gathers information about table to schema mapping # to understand table affinity # -# Each table / view needs to have assigned gitlab_schema. Names supported today: +# Each table / view needs to have assigned gitlab_schema. For example: # # - gitlab_shared - defines a set of tables that are found on all databases (data accessed is dependent on connection) # - gitlab_main / gitlab_ci - defines a set of tables that can only exist on a given application database # - gitlab_geo - defines a set of tables that can only exist on the geo database # - gitlab_internal - defines all internal tables of Rails and PostgreSQL # +# All supported GitLab schemas can be viewed in `db/gitlab_schemas/` and `ee/db/gitlab_schemas/` +# # Tables for the purpose of tests should be prefixed with `_test_my_table_name` module Gitlab @@ -17,8 +19,6 @@ module Gitlab module GitlabSchema UnknownSchemaError = Class.new(StandardError) - DICTIONARY_PATH = 'db/docs/' - def self.table_schemas!(tables) tables.map { |table| table_schema!(table) }.to_set end @@ -67,44 +67,50 @@ module Gitlab # All `pg_` tables are marked as `internal` return :gitlab_internal if table_name.start_with?('pg_') - - # Sometimes the name of an index can be interpreted as a table's name. - # For eg, if we execute "ALTER INDEX my_index..", my_index is interpreted as a table name. - # In such cases, we should return the schema of the database table actually - # holding that index. - index_name = table_name - derive_schema_from_index(index_name) end # rubocop:enable Metrics/CyclomaticComplexity - def self.dictionary_path_globs - [Rails.root.join(DICTIONARY_PATH, '*.yml')] + def self.table_schema!(name) + # rubocop:disable Gitlab/DocUrl + self.table_schema(name) || raise( + UnknownSchemaError, + "Could not find gitlab schema for table #{name}: Any new or deleted tables must be added to the database dictionary " \ + "See https://docs.gitlab.com/ee/development/database/database_dictionary.html" + ) + # rubocop:enable Gitlab/DocUrl end - def self.view_path_globs - [Rails.root.join(DICTIONARY_PATH, 'views', '*.yml')] + private_class_method def self.cross_access_allowed?(type, table_schemas) + table_schemas.any? do |schema| + extra_schemas = table_schemas - [schema] + extra_schemas -= Gitlab::Database.all_gitlab_schemas[schema]&.public_send(type) || [] # rubocop:disable GitlabSecurity/PublicSend + extra_schemas.empty? + end end - def self.deleted_views_path_globs - [Rails.root.join(DICTIONARY_PATH, 'deleted_views', '*.yml')] + def self.cross_joins_allowed?(table_schemas) + table_schemas.empty? || self.cross_access_allowed?(:allow_cross_joins, table_schemas) end - def self.deleted_tables_path_globs - [Rails.root.join(DICTIONARY_PATH, 'deleted_tables', '*.yml')] + def self.cross_transactions_allowed?(table_schemas) + table_schemas.empty? || self.cross_access_allowed?(:allow_cross_transactions, table_schemas) end - def self.views_and_tables_to_schema - @views_and_tables_to_schema ||= self.tables_to_schema.merge(self.views_to_schema) + def self.cross_foreign_key_allowed?(table_schemas) + self.cross_access_allowed?(:allow_cross_foreign_keys, table_schemas) end - def self.table_schema!(name) - # rubocop:disable Gitlab/DocUrl - self.table_schema(name) || raise( - UnknownSchemaError, - "Could not find gitlab schema for table #{name}: Any new or deleted tables must be added to the database dictionary " \ - "See https://docs.gitlab.com/ee/development/database/database_dictionary.html" - ) - # rubocop:enable Gitlab/DocUrl + def self.dictionary_paths + Gitlab::Database.all_database_connections + .values.map(&:db_docs_dir).uniq + end + + def self.dictionary_path_globs(scope) + self.dictionary_paths.map { |path| Rails.root.join(path, scope, '*.yml') } + end + + def self.views_and_tables_to_schema + @views_and_tables_to_schema ||= self.tables_to_schema.merge(self.views_to_schema) end def self.deleted_views_and_tables_to_schema @@ -112,36 +118,27 @@ module Gitlab end def self.deleted_tables_to_schema - @deleted_tables_to_schema ||= self.build_dictionary(self.deleted_tables_path_globs) + @deleted_tables_to_schema ||= self.build_dictionary('deleted_tables').to_h end def self.deleted_views_to_schema - @deleted_views_to_schema ||= self.build_dictionary(self.deleted_views_path_globs) + @deleted_views_to_schema ||= self.build_dictionary('deleted_views').to_h end def self.tables_to_schema - @tables_to_schema ||= self.build_dictionary(self.dictionary_path_globs) + @tables_to_schema ||= self.build_dictionary('').to_h end def self.views_to_schema - @views_to_schema ||= self.build_dictionary(self.view_path_globs) + @views_to_schema ||= self.build_dictionary('views').to_h end def self.schema_names @schema_names ||= self.views_and_tables_to_schema.values.to_set end - private_class_method def self.derive_schema_from_index(index_name) - index = Gitlab::Database::PostgresIndex.find_by(name: index_name, - schema: ApplicationRecord.connection.current_schema) - - return unless index - - table_schema(index.tablename) - end - - private_class_method def self.build_dictionary(path_globs) - Dir.glob(path_globs).each_with_object({}) do |file_path, dic| + def self.build_dictionary(scope) + Dir.glob(dictionary_path_globs(scope)).map do |file_path| data = YAML.load_file(file_path) key_name = data['table_name'] || data['view_name'] @@ -156,7 +153,7 @@ module Gitlab end # rubocop:enable Gitlab/DocUrl - dic[key_name] = data['gitlab_schema'].to_sym + [key_name, data['gitlab_schema'].to_sym] end end end |