class ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter
Константы
- INDEX_TYPES
- INDEX_USINGS
- LOST_CONNECTION_ERROR_MESSAGES
- NATIVE_DATABASE_TYPES
- QUOTED_FALSE
Публичные методы класса
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 139 class_attribute :emulate_booleans
По умолчанию, MysqlAdapter будет рассматривать все столбцы типа tinyint(1) как булевы. Если вы хотите отключить эту эмуляцию (что было по умолчанию в версиях 0.13.1 и ранее), вы можете добавить следующую строку в свой файл application.rb:
ActiveRecord::ConnectionAdapters::Mysql[2]Adapter.emulate_booleans = false
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 168
def initialize(connection, logger, connection_options, config)
super(connection, logger)
@connection_options, @config = connection_options, config
@quoted_column_names, @quoted_table_names = {}, {}
@visitor = Arel::Visitors::MySQL.new self
if self.class.type_cast_config_to_boolean(config.fetch(:prepared_statements) { true })
@prepared_statements = true
else
@prepared_statements = false
end
end FIXME: Сделать первый параметр более похожим для двух адаптеров
Публичные методы экземпляра
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 332 def begin_db_transaction execute "BEGIN" end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 336
def begin_isolated_db_transaction(isolation)
execute "SET TRANSACTION ISOLATION LEVEL #{transaction_isolation_levels.fetch(isolation)}"
begin_db_transaction
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 659
def case_insensitive_comparison(table, attribute, column, value)
if column.case_sensitive?
super
else
table[attribute].eq(value)
end
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 651
def case_sensitive_comparison(table, attribute, column, value)
if column.case_sensitive?
table[attribute].eq(value)
else
super
end
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 646 def case_sensitive_modifier(node, table_attribute) node = Arel::Nodes.build_quoted node, table_attribute Arel::Nodes::Bin.new(node) end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 528
def change_column_null(table_name, column_name, null, default = nil)
column = column_for(table_name, column_name)
unless null || default.nil?
execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
end
change_column table_name, column_name, column.sql_type, :null => null
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 404 def charset show_variable 'character_set_database' end
Возвращает кодировку символов базы данных.
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 310 def clear_cache! super reload_type_map end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 409 def collation show_variable 'collation_database' end
Возвращает стратегию сортировки базы данных.
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 383
def create_database(name, options = {})
if options[:collation]
execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}` COLLATE `#{options[:collation]}`"
else
execute "CREATE DATABASE `#{name}` DEFAULT CHARACTER SET `#{options[:charset] || 'utf8'}`"
end
end Создаёт новую базу данных MySQL с опциональными :charset и :collation. Кодировка по умолчанию utf8.
Пример:
create_database 'charset_test', charset: 'latin1', collation: 'latin1_bin' create_database 'matt_development' create_database 'matt_development', charset: :big5
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 399 def current_database select_value 'SELECT DATABASE() as db' end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 509
def drop_table(table_name, options = {})
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE #{quote_table_name(table_name)}#{' CASCADE' if options[:force] == :cascade}"
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 361 def empty_insert_statement_value "VALUES ()" end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 316
def execute(sql, name = nil)
log(sql, name) { @connection.query(sql) }
end Выполняет SQL-запрос в контексте этого соединения.
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 552
def foreign_keys(table_name)
fk_info = select_all " SELECT fk.referenced_table_name as 'to_table'
,fk.referenced_column_name as 'primary_key'
,fk.column_name as 'column'
,fk.constraint_name as 'name'
FROM information_schema.key_column_usage fk
WHERE fk.referenced_column_name is not null
AND fk.table_schema = '#{@config[:database]}'
AND fk.table_name = '#{table_name}'
".strip_heredoc
create_table_info = select_one("SHOW CREATE TABLE #{quote_table_name(table_name)}")["Create Table"]
fk_info.map do |row|
options = {
column: row['column'],
name: row['name'],
primary_key: row['primary_key']
}
options[:on_update] = extract_foreign_key_action(create_table_info, row['name'], "UPDATE")
options[:on_delete] = extract_foreign_key_action(create_table_info, row['name'], "DELETE")
ForeignKeyDefinition.new(table_name, row['to_table'], options)
end
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 229
def index_algorithms
{ default: 'ALGORITHM = DEFAULT', copy: 'ALGORITHM = COPY', inplace: 'ALGORITHM = INPLACE' }
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 225 def native_database_types NATIVE_DATABASE_TYPES end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 628
def pk_and_sequence_for(table)
execute_and_free("SHOW CREATE TABLE #{quote_table_name(table)}", 'SCHEMA') do |result|
create_table = each_hash(result).first[:"Create Table"]
if create_table.to_s =~ /PRIMARY KEY\s+(?:USING\s+\w+\s+)?\((.+)\)/
keys = $1.split(",").map { |key| key.delete('`"') }
keys.length == 1 ? [keys.first, nil] : nil
else
nil
end
end
end Возвращает первичный ключ и связанную последовательность таблицы.
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 641 def primary_key(table) pk_and_sequence = pk_and_sequence_for(table) pk_and_sequence && pk_and_sequence.first end
Возвращает только первичный ключ таблицы.
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 285
def quoted_date(value)
if supports_datetime_with_precision? && value.acts_like?(:time) && value.respond_to?(:usec)
"#{super}.#{sprintf("%06d", value.usec)}"
else
super
end
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 277 def quoted_false QUOTED_FALSE end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 269 def quoted_true QUOTED_TRUE end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 369
def recreate_database(name, options = {})
drop_database(name)
sql = create_database(name, options)
reconnect!
sql
end Удаляет базу данных, указанную в атрибуте name, и создаёт её заново, используя предоставленные options.
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 513
def rename_index(table_name, old_name, new_name)
if supports_rename_index?
validate_index_length!(table_name, new_name)
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME INDEX #{quote_table_name(old_name)} TO #{quote_table_name(new_name)}"
else
super
end
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 504
def rename_table(table_name, new_name)
execute "RENAME TABLE #{quote_table_name(table_name)} TO #{quote_table_name(new_name)}"
rename_table_indexes(table_name, new_name)
end Переименовывает таблицу.
Пример:
rename_table('octopuses', 'octopi')
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 57 def schema_creation SchemaCreation.new self end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 620
def show_variable(name)
variables = select_all("select @@#{name} as 'Value'", 'SCHEMA')
variables.first['Value'] unless variables.empty?
rescue ActiveRecord::StatementInvalid
nil
end ПОКАЗАТЬ ПЕРЕМЕННЫЕ, ТАКИЕ КАК 'name'
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 682 def strict_mode? self.class.type_cast_config_to_boolean(@config.fetch(:strict, true)) end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 221 def supports_datetime_with_precision? version >= '5.6.4' end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 213 def supports_foreign_keys? true end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 197 def supports_index_sort_order? true end
Технически MySQL позволяет создавать индексы с синтаксисом порядка сортировки, но в настоящее время (5.5) они ещё не реализованы
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 209 def supports_indexes_in_create? true end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 183 def supports_migrations? true end
Возвращает true, так как этот адаптер соединения поддерживает миграции.
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 187 def supports_primary_key? true end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 205 def supports_transaction_isolation? version >= '5.0.0' end
MySQL 4 технически поддерживает изоляцию транзакций, но она подвержена ошибке, где уровень транзакции сохраняется для всей сессии:
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 217 def supports_views? version >= '5.0.0' end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 428
def table_exists?(name)
return false unless name.present?
return true if tables(nil, nil, name).any?
name = name.to_s
schema, table = name.split('.', 2)
unless table # A table was provided without a schema
table = schema
schema = nil
end
tables(nil, schema, table).any?
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 424
def truncate(table_name, name = nil)
execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 581
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
case type.to_s
when 'binary'
case limit
when 0..0xfff; "varbinary(#{limit})"
when nil; "blob"
when 0x1000..0xffffffff; "blob(#{limit})"
else raise(ActiveRecordError, "No binary type has character length #{limit}")
end
when 'integer'
case limit
when 1; 'tinyint'
when 2; 'smallint'
when 3; 'mediumint'
when nil, 4, 11; 'int(11)' # compatibility with MySQL default
when 5..8; 'bigint'
else raise(ActiveRecordError, "No integer type has byte size #{limit}")
end
when 'text'
case limit
when 0..0xff; 'tinytext'
when nil, 0x100..0xffff; 'text'
when 0x10000..0xffffff; 'mediumtext'
when 0x1000000..0xffffffff; 'longtext'
else raise(ActiveRecordError, "No text type has character length #{limit}")
end
when 'datetime'
return super unless precision
case precision
when 0..6; "datetime(#{precision})"
else raise(ActiveRecordError, "No datetime type has precision of #{precision}. The allowed range of precision is from 0 to 6.")
end
else
super
end
end Преобразует логические типы Rails в специфичные для MySQL типы данных.
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 281 def unquoted_false 0 end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 273 def unquoted_true 1 end
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 686 def valid_type?(type) !native_database_types[type].nil? end
Защищенные методы экземпляра
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 792
def add_column_sql(table_name, column_name, type, options = {})
td = create_table_definition table_name, options[:temporary], options[:options]
cd = td.new_column_definition(column_name, type, options)
schema_creation.visit_AddColumn cd
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 756
def add_index_length(option_strings, column_names, options = {})
if options.is_a?(Hash) && length = options[:length]
case length
when Hash
column_names.each {|name| option_strings[name] += "(#{length[name]})" if length.has_key?(name) && length[name].present?}
when Integer
column_names.each {|name| option_strings[name] += "(#{length})"}
end
end
return option_strings
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 834
def add_index_sql(table_name, column_name, options = {})
index_name, index_type, index_columns = add_index_options(table_name, column_name, options)
"ADD #{index_type} INDEX #{index_name} (#{index_columns})"
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 844
def add_timestamps_sql(table_name, options = {})
[add_column_sql(table_name, :created_at, :datetime, options), add_column_sql(table_name, :updated_at, :datetime, options)]
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 798
def change_column_sql(table_name, column_name, type, options = {})
column = column_for(table_name, column_name)
unless options_include_default?(options)
options[:default] = column.default
end
unless options.has_key?(:null)
options[:null] = column.null
end
options[:name] = column.name
schema_creation.accept ChangeColumnDefinition.new column, type, options
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 769
def quoted_columns_for_index(column_names, options = {})
option_strings = Hash[column_names.map {|name| [name, '']}]
# add index length
option_strings = add_index_length(option_strings, column_names, options)
# add index sort order
option_strings = add_index_sort_order(option_strings, column_names, options)
column_names.map {|name| quote_column_name(name) + option_strings[name]}
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 826
def remove_column_sql(table_name, column_name, type = nil, options = {})
"DROP #{quote_column_name(column_name)}"
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 830
def remove_columns_sql(table_name, *column_names)
column_names.map {|column_name| remove_column_sql(table_name, column_name) }
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 839
def remove_index_sql(table_name, options = {})
index_name = index_name_for_remove(table_name, options)
"DROP INDEX #{index_name}"
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 848
def remove_timestamps_sql(table_name, options = {})
[remove_column_sql(table_name, :updated_at), remove_column_sql(table_name, :created_at)]
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 813
def rename_column_sql(table_name, column_name, new_column_name)
column = column_for(table_name, column_name)
options = {
name: new_column_name,
default: column.default,
null: column.null,
auto_increment: column.extra == "auto_increment"
}
current_type = select_one("SHOW COLUMNS FROM #{quote_table_name(table_name)} LIKE '#{column_name}'", 'SCHEMA')["Type"]
schema_creation.accept ChangeColumnDefinition.new column, current_type, options
end # File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 743
def subquery_for(key, select)
subsubselect = select.clone
subsubselect.projections = [key]
# Materialize subquery by adding distinct
# to work with MySQL 5.7.6 which sets optimizer_switch='derived_merge=on'
subsubselect.distinct unless select.limit || select.offset || select.orders.any?
subselect = Arel::SelectManager.new(select.engine)
subselect.project Arel.sql(key.name)
subselect.from subsubselect.as('__active_record_temp')
end MySQL слишком глуп, чтобы создавать временную таблицу для использования подзапроса, поэтому мы должны подсказать ему в виде подподзапроса. Фу!
# File activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb, line 781
def translate_exception(exception, message)
case error_number(exception)
when 1062
RecordNotUnique.new(message, exception)
when 1452
InvalidForeignKey.new(message, exception)
else
super
end
end
© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.