Skip to content

Instantly share code, notes, and snippets.

@dimaursu
Created January 12, 2015 15:08
Show Gist options
  • Save dimaursu/312714276d86b4e1fe18 to your computer and use it in GitHub Desktop.
Save dimaursu/312714276d86b4e1fe18 to your computer and use it in GitHub Desktop.
Crazy mysql migration
class SetMysqlToUnicodeMb4 < ActiveRecord::Migration
# Converts the tables and strings columns to utf8mb4, which is the true, full
# unicode support in MySQl
UTF8_PAIRS = Hash.new { |h,k| h[k] = [] }
tables = ActiveRecord::Base.connection.tables
tables.each do |table|
ActiveRecord::Base.connection.columns(table).each do |column|
# build a hash with all the columns that contain characters
if (column.type == :string) || (column.type == :text)
UTF8_PAIRS[table] << { :name => column.name, :type => column.sql_type }
end
end
end
def self.up
# shorten indexes regardless of the RDBMS provider - for consitency
shorten_indexes();
change_encoding('utf8mb4') if AppConfig.mysql?
end
def self.down
change_encoding('utf8') if AppConfig.mysql?
end
def change_encoding(encoding)
execute "ALTER DATABASE `#{ActiveRecord::Base.connection.current_database}` CHARACTER SET #{encoding};"
tables.each do |table|
execute "ALTER TABLE `#{table}` CHARACTER SET = #{encoding}"
end
UTF8_PAIRS.each do |table, columns|
columns.each do |column|
name = column[:name]
type = column[:type]
execute "ALTER TABLE `#{table}` CHANGE `#{name}` `#{name}` #{type} CHARACTER SET #{encoding} NULL;"
end
end
end
def shorten_indexes
require 'pry'
indexes = UTF8_PAIRS.collect do |table, columns|
ActiveRecord::Base.connection.indexes(table).collect do |index|
# compute the length of the new index < 767 bytes, which is a MySQL
# limitation on index column length, or 191 chars, 4byte each
width = 191
# index.columns -> ["invitation_service", "invitation_identifier"]
non_char_columns = index.columns.select do |icolumn|
columns.select { |column| icolumn == column[:name]}
end
width -= non_char_columns.length
# column width
width /= columns.length
col_lengths = {}
columns.each {|column| col_lengths[column[:name]] = width }
{
:name => index.name,
:table => index.table,
:columns => index.columns,
:col_lengths => col_lengths
}
end
end
indexes.flatten.each do |idx|
remove_index idx[:table], idx[:name]
add_index idx[:table], idx[:columns], :name => idx[:name], :length => idx[:col_lengths], using: :btree
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment