aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/lib/active_record.rb2
-rw-r--r--activerecord/lib/active_record/railties/databases.rake31
-rw-r--r--activerecord/lib/active_record/tasks/database_tasks.rb19
-rw-r--r--activerecord/lib/active_record/tasks/mysql_database_tasks.rb76
-rw-r--r--activerecord/lib/active_record/tasks/sqlite_database_tasks.rb19
-rw-r--r--activerecord/test/cases/mysql_rake_test.rb120
6 files changed, 230 insertions, 37 deletions
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index c6dc7db2e8..3b37b001f7 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -141,6 +141,8 @@ module ActiveRecord
extend ActiveSupport::Autoload
autoload :DatabaseTasks
+ autoload :SQLiteDatabaseTasks, 'active_record/tasks/sqlite_database_tasks'
+ autoload :MySQLDatabaseTasks, 'active_record/tasks/mysql_database_tasks'
end
autoload :TestCase
diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake
index b44d479fb6..662c84bfda 100644
--- a/activerecord/lib/active_record/railties/databases.rake
+++ b/activerecord/lib/active_record/railties/databases.rake
@@ -59,36 +59,7 @@ db_namespace = namespace :db do
rescue
case config['adapter']
when /mysql/
- if config['adapter'] =~ /jdbc/
- #FIXME After Jdbcmysql gives this class
- require 'active_record/railties/jdbcmysql_error'
- error_class = ArJdbcMySQL::Error
- else
- error_class = config['adapter'] =~ /mysql2/ ? Mysql2::Error : Mysql::Error
- end
- access_denied_error = 1045
- begin
- ActiveRecord::Base.establish_connection(config.merge('database' => nil))
- ActiveRecord::Base.connection.create_database(config['database'], mysql_creation_options(config))
- ActiveRecord::Base.establish_connection(config)
- rescue error_class => sqlerr
- if sqlerr.errno == access_denied_error
- print "#{sqlerr.error}. \nPlease provide the root password for your mysql installation\n>"
- root_password = $stdin.gets.strip
- grant_statement = "GRANT ALL PRIVILEGES ON #{config['database']}.* " \
- "TO '#{config['username']}'@'localhost' " \
- "IDENTIFIED BY '#{config['password']}' WITH GRANT OPTION;"
- ActiveRecord::Base.establish_connection(config.merge(
- 'database' => nil, 'username' => 'root', 'password' => root_password))
- ActiveRecord::Base.connection.create_database(config['database'], mysql_creation_options(config))
- ActiveRecord::Base.connection.execute grant_statement
- ActiveRecord::Base.establish_connection(config)
- else
- $stderr.puts sqlerr.error
- $stderr.puts "Couldn't create database for #{config.inspect}, charset: #{config['charset'] || @charset}, collation: #{config['collation'] || @collation}"
- $stderr.puts "(if you set the charset manually, make sure you have a matching collation)" if config['charset']
- end
- end
+ ActiveRecord::Tasks::DatabaseTasks.create config
when /postgresql/
@encoding = config['encoding'] || ENV['CHARSET'] || 'utf8'
begin
diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb
index a72ec0175b..d0d3ea12dd 100644
--- a/activerecord/lib/active_record/tasks/database_tasks.rb
+++ b/activerecord/lib/active_record/tasks/database_tasks.rb
@@ -1,14 +1,19 @@
class ActiveRecord::Tasks::DatabaseTasks
- def self.create(configuration)
- if File.exist?(configuration['database'])
- $stderr.puts "#{configuration['database']} already exists"
- return
- end
+ TASKS_PATTERNS = {
+ /mysql/ => ActiveRecord::Tasks::MySQLDatabaseTasks,
+ # /postgresql/ => ActiveRecord::Tasks::PostgreSQLTasker,
+ /sqlite/ => ActiveRecord::Tasks::SQLiteDatabaseTasks
+ }
- ActiveRecord::Base.establish_connection(configuration)
- ActiveRecord::Base.connection
+ def self.create(configuration)
+ class_for_adapter(configuration['adapter']).new(configuration).create
rescue Exception => e
$stderr.puts e, *(e.backtrace)
$stderr.puts "Couldn't create database for #{configuration.inspect}"
end
+
+ def self.class_for_adapter(adapter)
+ key = TASKS_PATTERNS.keys.detect { |key| adapter[key] }
+ TASKS_PATTERNS[key]
+ end
end
diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
new file mode 100644
index 0000000000..16d606d6fb
--- /dev/null
+++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb
@@ -0,0 +1,76 @@
+class ActiveRecord::Tasks::MySQLDatabaseTasks
+ DEFAULT_CHARSET = ENV['CHARSET'] || 'utf8'
+ DEFAULT_COLLATION = ENV['COLLATION'] || 'utf8_unicode_ci'
+ 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 error_class => error
+ raise error unless error.errno == ACCESS_DENIED_ERROR
+
+ $stdout.print error.error
+ establish_connection root_configuration_without_database
+ connection.create_database configuration['database'], creation_options
+ connection.execute grant_statement.gsub(/\s+/, ' ').strip
+ establish_connection configuration
+ rescue error_class => error
+ $stderr.puts error.error
+ $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['charset']
+ end
+
+ private
+
+ attr_reader :configuration
+
+ def configuration_without_database
+ configuration.merge('database' => nil)
+ end
+
+ def creation_options
+ {
+ :charset => (configuration['charset'] || DEFAULT_CHARSET),
+ :collation => (configuration['collation'] || DEFAULT_COLLATION)
+ }
+ end
+
+ def error_class
+ case configuration['adapter']
+ when /jdbc/
+ require 'active_record/railties/jdbcmysql_error'
+ error_class = ArJdbcMySQL::Error
+ when /mysql2/
+ Mysql2::Error
+ else
+ Mysql::Error
+ 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
+end
diff --git a/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
new file mode 100644
index 0000000000..882a4f98a9
--- /dev/null
+++ b/activerecord/lib/active_record/tasks/sqlite_database_tasks.rb
@@ -0,0 +1,19 @@
+class ActiveRecord::Tasks::SQLiteDatabaseTasks
+ def initialize(configuration)
+ @configuration = configuration
+ end
+
+ def create
+ if File.exist?(configuration['database'])
+ $stderr.puts "#{configuration['database']} already exists"
+ return
+ end
+
+ ActiveRecord::Base.establish_connection(configuration)
+ ActiveRecord::Base.connection
+ end
+
+ private
+
+ attr_reader :configuration
+end
diff --git a/activerecord/test/cases/mysql_rake_test.rb b/activerecord/test/cases/mysql_rake_test.rb
new file mode 100644
index 0000000000..fc49a16553
--- /dev/null
+++ b/activerecord/test/cases/mysql_rake_test.rb
@@ -0,0 +1,120 @@
+require 'cases/helper'
+
+module ActiveRecord
+ class MysqlDBCreateTest < ActiveRecord::TestCase
+ def setup
+ @connection = stub(:create_database => true)
+ @configuration = {
+ 'adapter' => 'mysql',
+ 'database' => 'my-app-db'
+ }
+
+ ActiveRecord::Base.stubs(:connection).returns(@connection)
+ ActiveRecord::Base.stubs(:establish_connection).returns(true)
+ end
+
+ def test_establishes_connection_without_database
+ ActiveRecord::Base.expects(:establish_connection).
+ with('adapter' => 'mysql', 'database' => nil)
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_creates_database_with_default_options
+ @connection.expects(:create_database).
+ with('my-app-db', {:charset => 'utf8', :collation => 'utf8_unicode_ci'})
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_creates_database_with_given_options
+ @connection.expects(:create_database).
+ with('my-app-db', {:charset => 'latin', :collation => 'latin_ci'})
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration.merge(
+ 'charset' => 'latin', 'collation' => 'latin_ci'
+ )
+ end
+
+ def test_establishes_connection_to_database
+ ActiveRecord::Base.expects(:establish_connection).with(@configuration)
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+ end
+
+ class MysqlDBCreateAsRootTest < ActiveRecord::TestCase
+ def setup
+ require 'mysql'
+
+ @connection = stub(:create_database => true, :execute => true)
+ @error = Mysql::Error.new "Invalid permissions"
+ @configuration = {
+ 'adapter' => 'mysql',
+ 'database' => 'my-app-db',
+ 'username' => 'pat',
+ 'password' => 'wossname'
+ }
+
+ $stdin.stubs(:gets).returns("secret\n")
+ $stdout.stubs(:print).returns(nil)
+ @error.stubs(:errno).returns(1045)
+ ActiveRecord::Base.stubs(:connection).returns(@connection)
+ ActiveRecord::Base.stubs(:establish_connection).raises(@error).then.
+ returns(true)
+ end
+
+ def test_root_password_is_requested
+ $stdin.expects(:gets).returns("secret\n")
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_connection_established_as_root
+ ActiveRecord::Base.expects(:establish_connection).with({
+ 'adapter' => 'mysql',
+ 'database' => nil,
+ 'username' => 'root',
+ 'password' => 'secret'
+ })
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_database_created_by_root
+ @connection.expects(:create_database).
+ with('my-app-db', :charset => 'utf8', :collation => 'utf8_unicode_ci')
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_grant_privileges_for_normal_user
+ @connection.expects(:execute).with("GRANT ALL PRIVILEGES ON my-app-db.* TO 'pat'@'localhost' IDENTIFIED BY 'wossname' WITH GRANT OPTION;")
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_connection_established_as_normal_user
+ ActiveRecord::Base.expects(:establish_connection).returns do
+ ActiveRecord::Base.expects(:establish_connection).with({
+ 'adapter' => 'mysql',
+ 'database' => 'my-app-db',
+ 'username' => 'pat',
+ 'password' => 'secret'
+ })
+
+ raise @error
+ end
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+
+ def test_sends_output_to_stderr_when_other_errors
+ @error.stubs(:errno).returns(42)
+
+ $stderr.expects(:puts).at_least_once.returns(nil)
+
+ ActiveRecord::Tasks::DatabaseTasks.create @configuration
+ end
+ end
+end