Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab_schema.rb « database « gitlab « lib - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: f23e0a5112df5c7cbeccd41f5ddd66d81e12692c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# frozen_string_literal: true

# This module gathers information about table to schema mapping
# to understand table affinity
#
# 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
  module Database
    module GitlabSchema
      UnknownSchemaError = Class.new(StandardError)

      def self.table_schemas!(tables)
        tables.map { |table| table_schema!(table) }.to_set
      end

      # Mainly used for test tables
      # It maps table names prefixes to gitlab_schemas.
      # The order of keys matter. Prefixes that contain other prefixes should come first.
      IMPLICIT_GITLAB_SCHEMAS = {
        '_test_gitlab_main_clusterwide_' => :gitlab_main_clusterwide,
        '_test_gitlab_main_cell_' => :gitlab_main_cell,
        '_test_gitlab_main_' => :gitlab_main,
        '_test_gitlab_ci_' => :gitlab_ci,
        '_test_gitlab_jh_' => :gitlab_jh,
        '_test_gitlab_embedding_' => :gitlab_embedding,
        '_test_gitlab_geo_' => :gitlab_geo,
        '_test_gitlab_pm_' => :gitlab_pm,
        '_test_' => :gitlab_shared,
        'pg_' => :gitlab_internal
      }.freeze

      # rubocop:disable Metrics/CyclomaticComplexity
      def self.table_schema(name)
        schema_name, table_name = name.split('.', 2) # Strip schema name like: `public.`

        # Most of names do not have schemas, ensure that this is table
        unless table_name
          table_name = schema_name
          schema_name = nil
        end

        # strip partition number of a form `loose_foreign_keys_deleted_records_1`
        table_name.gsub!(/_[0-9]+$/, '')

        # Tables and views that are properly mapped
        if gitlab_schema = views_and_tables_to_schema[table_name]
          return gitlab_schema
        end

        # Tables and views that are deleted, but we still need to reference them
        if gitlab_schema = deleted_views_and_tables_to_schema[table_name]
          return gitlab_schema
        end

        # Partitions that belong to the CI domain
        if table_name.start_with?('ci_') && gitlab_schema = views_and_tables_to_schema["p_#{table_name}"]
          return gitlab_schema
        end

        # All tables from `information_schema.` are marked as `internal`
        return :gitlab_internal if schema_name == 'information_schema'

        IMPLICIT_GITLAB_SCHEMAS.each do |prefix, gitlab_schema|
          return gitlab_schema if table_name.start_with?(prefix)
        end

        nil
      end
      # rubocop:enable Metrics/CyclomaticComplexity

      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.cell_local?(schema)
        Gitlab::Database.all_gitlab_schemas[schema.to_s].cell_local
      end

      def self.cross_joins_allowed?(table_schemas, all_tables)
        return true unless table_schemas.many?

        table_schemas.any? do |schema|
          schema_info = Gitlab::Database.all_gitlab_schemas[schema]
          next false unless schema_info

          schema_info.allow_cross_joins?(table_schemas, all_tables)
        end
      end

      def self.cross_transactions_allowed?(table_schemas, all_tables)
        return true unless table_schemas.many?

        table_schemas.any? do |schema|
          schema_info = Gitlab::Database.all_gitlab_schemas[schema]
          next false unless schema_info

          schema_info.allow_cross_transactions?(table_schemas, all_tables)
        end
      end

      def self.cross_foreign_key_allowed?(table_schemas, all_tables)
        return true if table_schemas.one?

        table_schemas.any? do |schema|
          schema_info = Gitlab::Database.all_gitlab_schemas[schema]
          next false unless schema_info

          schema_info.allow_cross_foreign_keys?(table_schemas, all_tables)
        end
      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
        @deleted_views_and_tables_to_schema ||= self.deleted_tables_to_schema.merge(self.deleted_views_to_schema)
      end

      def self.deleted_tables_to_schema
        @deleted_tables_to_schema ||= ::Gitlab::Database::Dictionary.entries('deleted_tables').to_name_and_schema_mapping
      end

      def self.deleted_views_to_schema
        @deleted_views_to_schema ||= ::Gitlab::Database::Dictionary.entries('deleted_views').to_name_and_schema_mapping
      end

      def self.tables_to_schema
        @tables_to_schema ||= ::Gitlab::Database::Dictionary.entries.to_name_and_schema_mapping
      end

      def self.views_to_schema
        @views_to_schema ||= ::Gitlab::Database::Dictionary.entries('views').to_name_and_schema_mapping
      end

      def self.schema_names
        @schema_names ||= self.views_and_tables_to_schema.values.to_set
      end
    end
  end
end

Gitlab::Database::GitlabSchema.prepend_mod