diff options
Diffstat (limited to 'activerecord/lib')
10 files changed, 113 insertions, 71 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 66d7f04fc3..7e16156408 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -16,38 +16,24 @@ module ActiveRecord ## # Builds a ConnectionSpecification from user input class Resolver # :nodoc: - attr_reader :config, :klass, :configurations + attr_reader :configurations - def initialize(config, configurations) - @config = config + def initialize(configurations) @configurations = configurations end - def spec - case config - when nil - raise AdapterNotSpecified unless defined?(Rails.env) - resolve_string_connection Rails.env - when Symbol, String - resolve_string_connection config.to_s - when Hash - resolve_hash_connection config - end - end - - private - def resolve_string_connection(spec) # :nodoc: - hash = configurations.fetch(spec) do |k| - connection_url_to_hash(k) + def resolve(config) + if config + resolve_connection config + elsif defined?(Rails.env) + resolve_env_connection Rails.env.to_sym + else + raise AdapterNotSpecified end - - raise(AdapterNotSpecified, "#{spec} database is not configured") unless hash - - resolve_hash_connection hash end - def resolve_hash_connection(spec) # :nodoc: - spec = spec.symbolize_keys + def spec(config) + spec = resolve(config).symbolize_keys raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter) @@ -61,12 +47,45 @@ module ActiveRecord end adapter_method = "#{spec[:adapter]}_connection" - ConnectionSpecification.new(spec, adapter_method) end - def connection_url_to_hash(url) # :nodoc: - config = URI.parse url + private + + def resolve_connection(spec) #:nodoc: + case spec + when Symbol, String + resolve_env_connection spec + when Hash + resolve_hash_connection spec + end + end + + def resolve_env_connection(spec) # :nodoc: + # Rails has historically accepted a string to mean either + # an environment key or a url spec, so we have deprecated + # this ambiguous behaviour and in the future this function + # can be removed in favor of resolve_string_connection and + # resolve_symbol_connection. + if config = configurations[spec.to_s] + if spec.is_a?(String) + ActiveSupport::Deprecation.warn "Passing a string to ActiveRecord::Base.establish_connection " \ + "for a configuration lookup is deprecated, please pass a symbol (#{spec.to_sym.inspect}) instead" + end + resolve_connection(config) + elsif spec.is_a?(String) + resolve_string_connection(spec) + else + raise(AdapterNotSpecified, "#{spec} database is not configured") + end + end + + def resolve_hash_connection(spec) # :nodoc: + spec + end + + def resolve_string_connection(spec) # :nodoc: + config = URI.parse spec adapter = config.scheme adapter = "postgresql" if adapter == "postgres" @@ -80,12 +99,12 @@ module ActiveRecord config.path.sub(%r{^/},"") end - spec = { :adapter => adapter, - :username => config.user, - :password => config.password, - :port => config.port, - :database => database, - :host => config.host } + spec = { "adapter" => adapter, + "username" => config.user, + "password" => config.password, + "port" => config.port, + "database" => database, + "host" => config.host } spec.reject!{ |_,value| value.blank? } @@ -94,8 +113,7 @@ module ActiveRecord spec.map { |key,value| spec[key] = uri_parser.unescape(value) if value.is_a?(String) } if config.query - options = Hash[config.query.split("&").map{ |pair| pair.split("=") }].symbolize_keys - + options = Hash[config.query.split("&").map{ |pair| pair.split("=") }] spec.merge!(options) end diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index e790f731ea..6d8e994654 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -18,6 +18,12 @@ module ActiveRecord client = Mysql2::Client.new(config) options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0] ConnectionAdapters::Mysql2Adapter.new(client, logger, options, config) + rescue Mysql2::Error => error + if error.message.include?("Unknown database") + raise ActiveRecord::NoDatabaseError.new(error.message) + else + raise error + end end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 760f1435eb..7dbaa272a3 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -34,6 +34,12 @@ module ActiveRecord default_flags |= Mysql::CLIENT_FOUND_ROWS if Mysql.const_defined?(:CLIENT_FOUND_ROWS) options = [host, username, password, database, port, socket, default_flags] ConnectionAdapters::MysqlAdapter.new(mysql, logger, options, config) + rescue Mysql::Error => error + if error.message.include?("Unknown database") + raise ActiveRecord::NoDatabaseError.new(error.message) + else + raise error + end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 95cd69d5ad..11a5eba464 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -46,7 +46,7 @@ module ActiveRecord # PostgreSQL-specific extensions to column definitions in a table. class PostgreSQLColumn < Column #:nodoc: attr_accessor :array - # Instantiates a new PostgreSQL column definition in a table. + def initialize(name, default, oid_type, sql_type = nil, null = true) @oid_type = oid_type default_value = self.class.extract_value_from_default(default) @@ -62,6 +62,14 @@ module ActiveRecord @default_function = default if has_default_function?(default_value, default) end + def number? + !array && super + end + + def text? + !array && super + end + # :stopdoc: class << self include ConnectionAdapters::PostgreSQLColumn::Cast diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index a02eda5603..92bb70ba53 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -31,6 +31,12 @@ module ActiveRecord db.busy_timeout(ConnectionAdapters::SQLite3Adapter.type_cast_config_to_integer(config[:timeout])) if config[:timeout] ConnectionAdapters::SQLite3Adapter.new(db, logger, config) + rescue Errno::ENOENT => error + if error.message.include?("No such file or directory") + raise ActiveRecord::NoDatabaseError.new(error.message) + else + raise error + end end end diff --git a/activerecord/lib/active_record/connection_handling.rb b/activerecord/lib/active_record/connection_handling.rb index a1943dfcb0..c4afadbd9b 100644 --- a/activerecord/lib/active_record/connection_handling.rb +++ b/activerecord/lib/active_record/connection_handling.rb @@ -32,11 +32,18 @@ module ActiveRecord # "postgres://myuser:mypass@localhost/somedatabase" # ) # + # In case <tt>ActiveRecord::Base.configurations</tt> is set (Rails + # automatically loads the contents of config/database.yml into it), + # a symbol can also be given as argument, representing a key in the + # configuration hash: + # + # ActiveRecord::Base.establish_connection(:production) + # # The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError # may be returned on an error. def establish_connection(spec = ENV["DATABASE_URL"]) - resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new spec, configurations - spec = resolver.spec + resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new configurations + spec = resolver.spec(spec) unless respond_to?(spec.adapter_method) raise AdapterNotFound, "database configuration specifies nonexistent #{spec.config[:adapter]} adapter" diff --git a/activerecord/lib/active_record/railtie.rb b/activerecord/lib/active_record/railtie.rb index ff98c829f4..2c796f97e6 100644 --- a/activerecord/lib/active_record/railtie.rb +++ b/activerecord/lib/active_record/railtie.rb @@ -43,11 +43,24 @@ module ActiveRecord namespace :db do task :load_config do ActiveRecord::Tasks::DatabaseTasks.db_dir = Rails.application.config.paths["db"].first - ActiveRecord::Tasks::DatabaseTasks.database_configuration = Rails.application.config.database_configuration ActiveRecord::Tasks::DatabaseTasks.migrations_paths = Rails.application.paths['db/migrate'].to_a ActiveRecord::Tasks::DatabaseTasks.fixtures_path = File.join Rails.root, 'test', 'fixtures' ActiveRecord::Tasks::DatabaseTasks.root = Rails.root + configuration = if ENV["DATABASE_URL"] + { Rails.env => ENV["DATABASE_URL"] } + else + Rails.application.config.database_configuration || {} + end + + resolver = ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(configuration) + + configuration.each do |key, value| + configuration[key] = resolver.resolve(value) if value + end + + ActiveRecord::Tasks::DatabaseTasks.database_configuration = configuration + if defined?(ENGINE_PATH) && engine = Rails::Engine.find(ENGINE_PATH) if engine.paths['db/migrate'].existent ActiveRecord::Tasks::DatabaseTasks.migrations_paths += engine.paths['db/migrate'].to_a diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index 0fdfed991c..90dfc177e5 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -14,11 +14,7 @@ db_namespace = namespace :db do desc 'Create the database from DATABASE_URL or config/database.yml for the current Rails.env (use db:create:all to create all databases in the config)' task :create => [:load_config] do - if ENV['DATABASE_URL'] - ActiveRecord::Tasks::DatabaseTasks.create_database_url - else - ActiveRecord::Tasks::DatabaseTasks.create_current - end + ActiveRecord::Tasks::DatabaseTasks.create_current end namespace :drop do @@ -29,11 +25,7 @@ db_namespace = namespace :db do desc 'Drops the database using DATABASE_URL or the current Rails.env (use db:drop:all to drop all databases)' task :drop => [:load_config] do - if ENV['DATABASE_URL'] - ActiveRecord::Tasks::DatabaseTasks.drop_database_url - else - ActiveRecord::Tasks::DatabaseTasks.drop_current - end + ActiveRecord::Tasks::DatabaseTasks.drop_current end desc "Migrate the database (options: VERSION=x, VERBOSE=false, SCOPE=blog)." diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb index cab8fd745a..dacaec26b7 100644 --- a/activerecord/lib/active_record/sanitization.rb +++ b/activerecord/lib/active_record/sanitization.rb @@ -100,8 +100,9 @@ module ActiveRecord # { status: nil, group_id: 1 } # # => "status = NULL , group_id = 1" def sanitize_sql_hash_for_assignment(attrs, table) + c = connection attrs.map do |attr, value| - "#{connection.quote_table_name_for_assignment(table, attr)} = #{quote_bound_value(value)}" + "#{c.quote_table_name_for_assignment(table, attr)} = #{quote_bound_value(value, c, columns_hash[attr.to_s])}" end.join(', ') end @@ -152,8 +153,10 @@ module ActiveRecord end end - def quote_bound_value(value, c = connection) #:nodoc: - if value.respond_to?(:map) && !value.acts_like?(:string) + def quote_bound_value(value, c = connection, column = nil) #:nodoc: + if column + c.quote(value, column) + elsif value.respond_to?(:map) && !value.acts_like?(:string) if value.respond_to?(:empty?) && value.empty? c.quote(nil) else diff --git a/activerecord/lib/active_record/tasks/database_tasks.rb b/activerecord/lib/active_record/tasks/database_tasks.rb index be7d496d15..06592eece2 100644 --- a/activerecord/lib/active_record/tasks/database_tasks.rb +++ b/activerecord/lib/active_record/tasks/database_tasks.rb @@ -56,11 +56,7 @@ module ActiveRecord if options.has_key?(:config) @current_config = options[:config] else - @current_config ||= if ENV['DATABASE_URL'] - database_url_config - else - ActiveRecord::Base.configurations[options[:env]] - end + @current_config ||= ActiveRecord::Base.configurations[options[:env]] end end @@ -85,10 +81,6 @@ module ActiveRecord ActiveRecord::Base.establish_connection environment end - def create_database_url - create database_url_config - end - def drop(*arguments) configuration = arguments.first class_for_adapter(configuration['adapter']).new(*arguments).drop @@ -107,10 +99,6 @@ module ActiveRecord } end - def drop_database_url - drop database_url_config - end - def charset_current(environment = env) charset ActiveRecord::Base.configurations[environment] end @@ -165,11 +153,6 @@ module ActiveRecord private - def database_url_config - @database_url_config ||= - ConnectionAdapters::ConnectionSpecification::Resolver.new(ENV["DATABASE_URL"], {}).spec.config.stringify_keys - end - def class_for_adapter(adapter) key = @tasks.keys.detect { |pattern| adapter[pattern] } unless key |