Module: Gitlab::Database::SchemaHelpers

Instance Method Summary collapse

Instance Method Details

#assert_not_in_transaction_block(scope:) ⇒ Object



88
89
90
91
92
93
94
# File 'lib/gitlab/database/schema_helpers.rb', line 88

def assert_not_in_transaction_block(scope:)
  return unless transaction_open?

  raise "#{scope} operations can not be run inside a transaction block, " \
    "you can disable transaction blocks by calling disable_ddl_transaction! " \
    "in the body of your migration class"
end

#create_comment(type, name, text) ⇒ Object



71
72
73
# File 'lib/gitlab/database/schema_helpers.rb', line 71

def create_comment(type, name, text)
  execute("COMMENT ON #{type} #{name} IS '#{text}'")
end

#create_trigger(table_name, name, function_name, fires:) ⇒ Object



35
36
37
38
39
40
41
42
43
# File 'lib/gitlab/database/schema_helpers.rb', line 35

def create_trigger(table_name, name, function_name, fires:)
  execute(<<~SQL)
    CREATE TRIGGER #{name}
    #{fires} ON #{table_name}
    FOR EACH ROW
    #{yield if block_given?}
    EXECUTE FUNCTION #{function_name}()
  SQL
end

#create_trigger_function(name, replace: true) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
# File 'lib/gitlab/database/schema_helpers.rb', line 6

def create_trigger_function(name, replace: true)
  replace_clause = optional_clause(replace, "OR REPLACE")
  execute(<<~SQL)
    CREATE #{replace_clause} FUNCTION #{name}()
    RETURNS TRIGGER AS
    $$
    BEGIN
    #{yield}
    END
    $$ LANGUAGE PLPGSQL
  SQL
end

#drop_function(name, if_exists: true) ⇒ Object



61
62
63
64
# File 'lib/gitlab/database/schema_helpers.rb', line 61

def drop_function(name, if_exists: true)
  exists_clause = optional_clause(if_exists, "IF EXISTS")
  execute("DROP FUNCTION #{exists_clause} #{name}()")
end

#drop_trigger(table_name, name, if_exists: true) ⇒ Object



66
67
68
69
# File 'lib/gitlab/database/schema_helpers.rb', line 66

def drop_trigger(table_name, name, if_exists: true)
  exists_clause = optional_clause(if_exists, "IF EXISTS")
  execute("DROP TRIGGER #{exists_clause} #{name} ON #{table_name}")
end

#find_all_id_columns_sqlObject



96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/gitlab/database/schema_helpers.rb', line 96

def find_all_id_columns_sql
  <<~SQL.strip
    SELECT table_name, column_name, data_type, column_default FROM information_schema.columns a
    WHERE a.table_schema = 'public'
    AND (
      -- columns like "id" and "project_id"
      (a.data_type = 'integer' AND (a.column_name = 'id' OR a.column_name LIKE '%\\_id'))
      OR
      -- columns like "traversal_ids"
      (a.data_type = 'ARRAY' AND a.udt_name = '_int4' AND a.column_name LIKE '%\\_ids')
    )
    AND NOT EXISTS (
      -- skip columns when migration is in progress
      SELECT 1 FROM information_schema.columns b WHERE b.table_schema = a.table_schema AND b.table_name = a.table_name
      AND b.data_type = 'bigint' AND b.column_name = (a.column_name || '_convert_to_bigint')
    )
    AND NOT EXISTS (
      -- skip columns from partitioned tables
      SELECT 1 FROM postgres_partitions c WHERE c.schema = 'public' AND c.name = a.table_name
    )
    ORDER BY table_schema, table_name, column_name
  SQL
end

#function_exists?(name) ⇒ Boolean

Returns:

  • (Boolean)


31
32
33
# File 'lib/gitlab/database/schema_helpers.rb', line 31

def function_exists?(name)
  !!connection.select_value("SELECT 1 FROM pg_proc WHERE proname = '#{name}'")
end

#object_name(table, type) ⇒ Object



81
82
83
84
85
86
# File 'lib/gitlab/database/schema_helpers.rb', line 81

def object_name(table, type)
  identifier = "#{table}_#{type}"
  hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10)

  "#{type}_#{hashed_identifier}"
end

#reset_all_trigger_functions(table_name) ⇒ Object



23
24
25
26
27
28
29
# File 'lib/gitlab/database/schema_helpers.rb', line 23

def reset_all_trigger_functions(table_name)
  triggers = find_table_triggers(table_name)

  triggers.each do |trigger|
    reset_trigger_function(trigger['function_name'])
  end
end

#reset_trigger_function(function_name) ⇒ Object



19
20
21
# File 'lib/gitlab/database/schema_helpers.rb', line 19

def reset_trigger_function(function_name)
  execute("ALTER FUNCTION #{quote_table_name(function_name)} RESET ALL")
end

#tmp_table_name(base) ⇒ Object



75
76
77
78
79
# File 'lib/gitlab/database/schema_helpers.rb', line 75

def tmp_table_name(base)
  hashed_base = Digest::SHA256.hexdigest(base).first(10)

  "#{base}_#{hashed_base}"
end

#trigger_exists?(table_name, name, schema = nil) ⇒ Boolean

Returns:

  • (Boolean)


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/gitlab/database/schema_helpers.rb', line 45

def trigger_exists?(table_name, name, schema = nil)
  result = connection.select_value(<<~SQL.squish)
    SELECT true
    FROM pg_catalog.pg_trigger trgr
      INNER JOIN pg_catalog.pg_class rel
        ON trgr.tgrelid = rel.oid
      INNER JOIN pg_catalog.pg_namespace nsp
        ON nsp.oid = rel.relnamespace
    WHERE nsp.nspname = #{connection.quote(schema || connection.current_schema)}
      AND rel.relname = #{connection.quote(table_name)}
      AND trgr.tgname = #{connection.quote(name)}
  SQL

  !!result
end