5eab624d3c
This adds a bunch of checks to migrations that may create or drop triggers. Dropping triggers/functions is done using "IF EXISTS" so we don't throw an error if the object in question has already been dropped. We now also raise a custom error (message) when the user does not have TRIGGER privileges. This should prevent the schema from entering an inconsistent state while also providing the user with enough information on how to solve the problem. The recommendation of using SUPERUSER permissions is a bit extreme but we require this anyway (Omnibus also configures users with this permission). Fixes https://gitlab.com/gitlab-org/gitlab-ce/issues/36633
152 lines
3.6 KiB
Ruby
152 lines
3.6 KiB
Ruby
module Gitlab
|
|
module Database
|
|
# The max value of INTEGER type is the same between MySQL and PostgreSQL:
|
|
# https://www.postgresql.org/docs/9.2/static/datatype-numeric.html
|
|
# http://dev.mysql.com/doc/refman/5.7/en/integer-types.html
|
|
MAX_INT_VALUE = 2147483647
|
|
|
|
def self.config
|
|
ActiveRecord::Base.configurations[Rails.env]
|
|
end
|
|
|
|
def self.username
|
|
config['username'] || ENV['USER']
|
|
end
|
|
|
|
def self.database_name
|
|
config['database']
|
|
end
|
|
|
|
def self.adapter_name
|
|
config['adapter']
|
|
end
|
|
|
|
def self.mysql?
|
|
adapter_name.casecmp('mysql2').zero?
|
|
end
|
|
|
|
def self.postgresql?
|
|
adapter_name.casecmp('postgresql').zero?
|
|
end
|
|
|
|
def self.version
|
|
database_version.match(/\A(?:PostgreSQL |)([^\s]+).*\z/)[1]
|
|
end
|
|
|
|
def self.join_lateral_supported?
|
|
postgresql? && version.to_f >= 9.3
|
|
end
|
|
|
|
def self.nulls_last_order(field, direction = 'ASC')
|
|
order = "#{field} #{direction}"
|
|
|
|
if postgresql?
|
|
order << ' NULLS LAST'
|
|
else
|
|
# `field IS NULL` will be `0` for non-NULL columns and `1` for NULL
|
|
# columns. In the (default) ascending order, `0` comes first.
|
|
order.prepend("#{field} IS NULL, ") if direction == 'ASC'
|
|
end
|
|
|
|
order
|
|
end
|
|
|
|
def self.nulls_first_order(field, direction = 'ASC')
|
|
order = "#{field} #{direction}"
|
|
|
|
if postgresql?
|
|
order << ' NULLS FIRST'
|
|
else
|
|
# `field IS NULL` will be `0` for non-NULL columns and `1` for NULL
|
|
# columns. In the (default) ascending order, `0` comes first.
|
|
order.prepend("#{field} IS NULL, ") if direction == 'DESC'
|
|
end
|
|
|
|
order
|
|
end
|
|
|
|
def self.random
|
|
postgresql? ? "RANDOM()" : "RAND()"
|
|
end
|
|
|
|
def self.true_value
|
|
if postgresql?
|
|
"'t'"
|
|
else
|
|
1
|
|
end
|
|
end
|
|
|
|
def self.false_value
|
|
if postgresql?
|
|
"'f'"
|
|
else
|
|
0
|
|
end
|
|
end
|
|
|
|
def self.with_connection_pool(pool_size)
|
|
pool = create_connection_pool(pool_size)
|
|
|
|
begin
|
|
yield(pool)
|
|
ensure
|
|
pool.disconnect!
|
|
end
|
|
end
|
|
|
|
def self.bulk_insert(table, rows)
|
|
return if rows.empty?
|
|
|
|
keys = rows.first.keys
|
|
columns = keys.map { |key| connection.quote_column_name(key) }
|
|
|
|
tuples = rows.map do |row|
|
|
row.values_at(*keys).map { |value| connection.quote(value) }
|
|
end
|
|
|
|
connection.execute <<-EOF
|
|
INSERT INTO #{table} (#{columns.join(', ')})
|
|
VALUES #{tuples.map { |tuple| "(#{tuple.join(', ')})" }.join(', ')}
|
|
EOF
|
|
end
|
|
|
|
# pool_size - The size of the DB pool.
|
|
# host - An optional host name to use instead of the default one.
|
|
def self.create_connection_pool(pool_size, host = nil)
|
|
# See activerecord-4.2.7.1/lib/active_record/connection_adapters/connection_specification.rb
|
|
env = Rails.env
|
|
original_config = ActiveRecord::Base.configurations
|
|
|
|
env_config = original_config[env].merge('pool' => pool_size)
|
|
env_config['host'] = host if host
|
|
|
|
config = original_config.merge(env => env_config)
|
|
|
|
spec =
|
|
ActiveRecord::
|
|
ConnectionAdapters::
|
|
ConnectionSpecification::Resolver.new(config).spec(env.to_sym)
|
|
|
|
ActiveRecord::ConnectionAdapters::ConnectionPool.new(spec)
|
|
end
|
|
|
|
def self.connection
|
|
ActiveRecord::Base.connection
|
|
end
|
|
|
|
private_class_method :connection
|
|
|
|
def self.database_version
|
|
row = connection.execute("SELECT VERSION()").first
|
|
|
|
if postgresql?
|
|
row['version']
|
|
else
|
|
row.first
|
|
end
|
|
end
|
|
|
|
private_class_method :database_version
|
|
end
|
|
end
|