module ODBCAdapter module Adapters # Overrides specific to MySQL. Mostly taken from # ActiveRecord::ConnectionAdapters::MySQLAdapter class MySQLODBCAdapter < ActiveRecord::ConnectionAdapters::ODBCAdapter class BindSubstitution < Arel::Visitors::MySQL include Arel::Visitors::BindVisitor end PRIMARY_KEY = 'INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY' def limited_update_conditions(where_sql, _quoted_table_name, _quoted_primary_key) where_sql end # Taken from ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter def join_to_update(update, select) #:nodoc: if select.limit || select.offset || select.orders.any? subsubselect = select.clone subsubselect.projections = [update.key] subselect = Arel::SelectManager.new(select.engine) subselect.project Arel.sql(update.key.name) subselect.from subsubselect.as('__active_record_temp') update.where update.key.in(subselect) else update.table select.source update.wheres = select.constraints end end # Quotes a string, escaping any ' (single quote) and \ (backslash) # characters. def quote_string(string) string.gsub(/\\/, '\&\&').gsub(/'/, "''") end def disable_referential_integrity(&block) #:nodoc: old = select_value("SELECT @@FOREIGN_KEY_CHECKS") begin update("SET FOREIGN_KEY_CHECKS = 0") yield ensure update("SET FOREIGN_KEY_CHECKS = #{old}") end end # Create a new MySQL database with optional :charset and :collation. # Charset defaults to utf8. # # Example: # create_database 'charset_test', :charset => 'latin1', :collation => 'latin1_bin' # create_database 'matt_development' # create_database 'matt_development', :charset => :big5 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 # Drops a MySQL database. # # Example: # drop_database('sebastian_development') def drop_database(name) #:nodoc: execute("DROP DATABASE IF EXISTS `#{name}`") end def create_table(name, options = {}) super(name, { options: 'ENGINE=InnoDB' }.merge(options)) end # Renames a table. def rename_table(name, new_name) execute("RENAME TABLE #{quote_table_name(name)} TO #{quote_table_name(new_name)}") end def change_column(table_name, column_name, type, options = {}) # column_name.to_s used in case column_name is a symbol unless options_include_default?(options) options[:default] = columns(table_name).find { |c| c.name == column_name.to_s }.default end change_column_sql = "ALTER TABLE #{table_name} CHANGE #{column_name} #{column_name} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}" add_column_options!(change_column_sql, options) execute(change_column_sql) end def change_column_default(table_name, column_name, default) col = columns(table_name).detect { |c| c.name == column_name.to_s } change_column(table_name, column_name, col.type, default: default, limit: col.limit, precision: col.precision, scale: col.scale) end def rename_column(table_name, column_name, new_column_name) col = columns(table_name).detect { |c| c.name == column_name.to_s } current_type = col.sql_type current_type << "(#{col.limit})" if col.limit execute("ALTER TABLE #{table_name} CHANGE #{column_name} #{new_column_name} #{current_type}") end def indexes(table_name, name = nil) # Skip primary key indexes super(table_name, name).delete_if { |i| i.unique && i.name =~ /^PRIMARY$/ } end def options_include_default?(options) # MySQL 5.x doesn't allow DEFAULT NULL for first timestamp column in a table if options.include?(:default) && options[:default].nil? if options.include?(:column) && options[:column].sql_type =~ /timestamp/i options.delete(:default) end end super(options) end def structure_dump select_all("SHOW FULL TABLES WHERE Table_type = 'BASE TABLE'").map do |table| table.delete('Table_type') sql = "SHOW CREATE TABLE #{quote_table_name(table.to_a.first.last)}" exec_query(sql).first['Create Table'] + ";\n\n" end.join end protected def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) super id_value || last_inserted_id(nil) end def last_inserted_id(_result) @connection.last_id end end end end