1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
# frozen_string_literal: true
module ActiveRecord
module Tasks # :nodoc:
class MySQLDatabaseTasks # :nodoc:
ACCESS_DENIED_ERROR = 1045
delegate :connection, :establish_connection, to: ActiveRecord::Base
def initialize(configuration)
@configuration = configuration
end
def create
establish_connection configuration_without_database
connection.create_database configuration["database"], creation_options
establish_connection configuration
rescue ActiveRecord::StatementInvalid => error
if error.message.include?("database exists")
raise DatabaseAlreadyExists
else
raise
end
rescue error_class => error
if error.respond_to?(:errno) && error.errno == ACCESS_DENIED_ERROR
$stdout.print error.message
establish_connection root_configuration_without_database
connection.create_database configuration["database"], creation_options
if configuration["username"] != "root"
connection.execute grant_statement.gsub(/\s+/, " ").strip
end
establish_connection configuration
else
$stderr.puts error.inspect
$stderr.puts "Couldn't create database for #{configuration.inspect}, #{creation_options.inspect}"
$stderr.puts "(If you set the charset manually, make sure you have a matching collation)" if configuration["encoding"]
end
end
def drop
establish_connection configuration
connection.drop_database configuration["database"]
end
def purge
establish_connection configuration
connection.recreate_database configuration["database"], creation_options
end
def charset
connection.charset
end
def collation
connection.collation
end
def structure_dump(filename, extra_flags)
args = prepare_command_options
args.concat(["--result-file", "#{filename}"])
args.concat(["--no-data"])
args.concat(["--routines"])
args.concat(["--skip-comments"])
ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
if ignore_tables.any?
args += ignore_tables.map { |table| "--ignore-table=#{configuration['database']}.#{table}" }
end
args.concat(["#{configuration['database']}"])
args.unshift(*extra_flags) if extra_flags
run_cmd("mysqldump", args, "dumping")
end
def structure_load(filename, extra_flags)
args = prepare_command_options
args.concat(["--execute", %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}])
args.concat(["--database", "#{configuration['database']}"])
args.unshift(*extra_flags) if extra_flags
run_cmd("mysql", args, "loading")
end
private
def configuration
@configuration
end
def configuration_without_database
configuration.merge("database" => nil)
end
def creation_options
Hash.new.tap do |options|
options[:charset] = configuration["encoding"] if configuration.include? "encoding"
options[:collation] = configuration["collation"] if configuration.include? "collation"
end
end
def error_class
if configuration["adapter"].include?("jdbc")
require_relative "../railties/jdbcmysql_error"
ArJdbcMySQL::Error
elsif defined?(Mysql2)
Mysql2::Error
else
StandardError
end
end
def grant_statement
<<-SQL
GRANT ALL PRIVILEGES ON `#{configuration['database']}`.*
TO '#{configuration['username']}'@'localhost'
IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION;
SQL
end
def root_configuration_without_database
configuration_without_database.merge(
"username" => "root",
"password" => root_password
)
end
def root_password
$stdout.print "Please provide the root password for your MySQL installation\n>"
$stdin.gets.strip
end
def prepare_command_options
args = {
"host" => "--host",
"port" => "--port",
"socket" => "--socket",
"username" => "--user",
"password" => "--password",
"encoding" => "--default-character-set",
"sslca" => "--ssl-ca",
"sslcert" => "--ssl-cert",
"sslcapath" => "--ssl-capath",
"sslcipher" => "--ssl-cipher",
"sslkey" => "--ssl-key"
}.map { |opt, arg| "#{arg}=#{configuration[opt]}" if configuration[opt] }.compact
args
end
def run_cmd(cmd, args, action)
fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args)
end
def run_cmd_error(cmd, args, action)
msg = "failed to execute: `#{cmd}`\n".dup
msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
msg
end
end
end
end
|