diff options
author | Xavier Noria <fxn@hashref.com> | 2010-06-28 00:12:15 +0200 |
---|---|---|
committer | Xavier Noria <fxn@hashref.com> | 2010-06-28 00:12:15 +0200 |
commit | 4329f8133fee8e4f3e558787f67de59f0c4a4dd1 (patch) | |
tree | 346ef7340d8348e50d119ca749a16c1654c20a08 /activerecord/lib/active_record/connection_adapters | |
parent | c37f7d66e49ffe5ac2115cc30e5529fd1c2924a8 (diff) | |
parent | ebee77a28a7267d5f23a28ba23c1eb88a2d7d527 (diff) | |
download | rails-4329f8133fee8e4f3e558787f67de59f0c4a4dd1.tar.gz rails-4329f8133fee8e4f3e558787f67de59f0c4a4dd1.tar.bz2 rails-4329f8133fee8e4f3e558787f67de59f0c4a4dd1.zip |
Merge remote branch 'rails/master'
Diffstat (limited to 'activerecord/lib/active_record/connection_adapters')
8 files changed, 90 insertions, 42 deletions
diff --git a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb index 979ed52f4a..c2d79a421d 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb @@ -144,7 +144,9 @@ module ActiveRecord @connections.each do |conn| conn.disconnect! if conn.requires_reloading? end - @connections = [] + @connections.delete_if do |conn| + conn.requires_reloading? + end end # Verify active connections and remove and disconnect connections diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index 7d58bc2adf..7691b6a788 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -582,6 +582,11 @@ module ActiveRecord @base.add_column(@table_name, column_name, type, options) end + # Checks to see if a column exists. See SchemaStatements#column_exists? + def column_exists?(column_name, type = nil, options = nil) + @base.column_exists?(@table_name, column_name, type, options) + end + # Adds a new index to the table. +column_name+ can be a single Symbol, or # an Array of Symbols. See SchemaStatements#add_index # @@ -596,6 +601,11 @@ module ActiveRecord @base.add_index(@table_name, column_name, options) end + # Checks to see if an index exists. See SchemaStatements#index_exists? + def index_exists?(column_name, options = {}) + @base.index_exists?(@table_name, column_name, options) + end + # Adds timestamps (created_at and updated_at) columns to the table. See SchemaStatements#add_timestamps # ===== Example # t.timestamps diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb index d3499cea72..0216a8f4ac 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -24,10 +24,53 @@ module ActiveRecord # Returns an array of indexes for the given table. # def indexes(table_name, name = nil) end + # Checks to see if an index exists on a table for a given index definition + # + # === Examples + # # Check an index exists + # index_exists?(:suppliers, :company_id) + # + # # Check an index on multiple columns exists + # index_exists?(:suppliers, [:company_id, :company_type]) + # + # # Check a unique index exists + # index_exists?(:suppliers, :company_id, :unique => true) + # + # # Check an index with a custom name exists + # index_exists?(:suppliers, :company_id, :name => "idx_company_id" + def index_exists?(table_name, column_name, options = {}) + column_names = Array.wrap(column_name) + index_name = options.key?(:name) ? options[:name].to_s : index_name(table_name, :column => column_names) + if options[:unique] + indexes(table_name).any?{ |i| i.unique && i.name == index_name } + else + indexes(table_name).any?{ |i| i.name == index_name } + end + end + # Returns an array of Column objects for the table specified by +table_name+. # See the concrete implementation for details on the expected parameter values. def columns(table_name, name = nil) end + # Checks to see if a column exists in a given table. + # + # === Examples + # # Check a column exists + # column_exists?(:suppliers, :name) + # + # # Check a column exists of a particular type + # column_exists?(:suppliers, :name, :string) + # + # # Check a column exists with a specific definition + # column_exists?(:suppliers, :name, :string, :limit => 100) + def column_exists?(table_name, column_name, type = nil, options = {}) + columns(table_name).any?{ |c| c.name == column_name.to_s && + (!type || c.type == type) && + (!options[:limit] || c.limit == options[:limit]) && + (!options[:precision] || c.precision == options[:precision]) && + (!options[:scale] || c.scale == options[:scale]) } + end + # Creates a new table with the name +table_name+. +table_name+ may either # be a String or a Symbol. # @@ -205,6 +248,7 @@ module ActiveRecord # remove_column(:suppliers, :qualification) # remove_columns(:suppliers, :qualification, :experience) def remove_column(table_name, *column_names) + raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty? column_names.flatten.each do |column_name| execute "ALTER TABLE #{quote_table_name(table_name)} DROP #{quote_column_name(column_name)}" end @@ -292,7 +336,7 @@ module ActiveRecord @logger.warn("Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{index_name_length} characters. Skipping.") return end - if index_exists?(table_name, index_name, false) + if index_name_exists?(table_name, index_name, false) @logger.warn("Index name '#{index_name}' on table '#{table_name}' already exists. Skipping.") return end @@ -313,7 +357,7 @@ module ActiveRecord # remove_index :accounts, :name => :by_branch_party def remove_index(table_name, options = {}) index_name = index_name(table_name, options) - unless index_exists?(table_name, index_name, true) + unless index_name_exists?(table_name, index_name, true) @logger.warn("Index name '#{index_name}' on table '#{table_name}' does not exist. Skipping.") return end @@ -350,11 +394,11 @@ module ActiveRecord end end - # Verify the existence of an index. + # Verify the existence of an index with a given name. # # The default argument is returned if the underlying implementation does not define the indexes method, # as there's no way to determine the correct answer in that case. - def index_exists?(table_name, index_name, default) + def index_name_exists?(table_name, index_name, default) return default unless respond_to?(:indexes) indexes(table_name).detect { |i| i.name == index_name } end diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 4ee9fee4a9..be8d1bd76b 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -107,7 +107,7 @@ module ActiveRecord # REFERENTIAL INTEGRITY ==================================== # Override to turn off referential integrity while executing <tt>&block</tt>. - def disable_referential_integrity(&block) + def disable_referential_integrity yield end @@ -142,9 +142,10 @@ module ActiveRecord # this should be overridden by concrete adapters end - # Returns true if its safe to reload the connection between requests for development mode. + # Returns true if its required to reload the connection between requests for development mode. + # This is not the case for Ruby/MySQL and it's not necessary for any adapters except SQLite. def requires_reloading? - true + false end # Checks whether the connection to the database is still active (i.e. not stale). diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index 7c7bc5e292..aa3626a37e 100644 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -219,7 +219,7 @@ module ActiveRecord # REFERENTIAL INTEGRITY ==================================== - def disable_referential_integrity(&block) #:nodoc: + def disable_referential_integrity #:nodoc: old = select_value("SELECT @@FOREIGN_KEY_CHECKS") begin diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index e84242601b..2fe2ae7136 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -216,7 +216,10 @@ module ActiveRecord super(connection, logger) @connection_parameters, @config = connection_parameters, config + # @local_tz is initialized as nil to avoid warnings when connect tries to use it + @local_tz = nil connect + @local_tz = execute('SHOW TIME ZONE').first["TimeZone"] end # Is this connection alive and ready for queries? @@ -372,7 +375,7 @@ module ActiveRecord return false end - def disable_referential_integrity(&block) #:nodoc: + def disable_referential_integrity #:nodoc: if supports_disable_referential_integrity?() then execute(tables.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";")) end @@ -606,27 +609,22 @@ module ActiveRecord SQL - indexes = [] - - indexes = result.map do |row| + result.map do |row| index_name = row[0] unique = row[1] == 't' indkey = row[2].split(" ") oid = row[3] - columns = query(<<-SQL, "Columns for index #{row[0]} on #{table_name}").inject({}) {|attlist, r| attlist[r[1]] = r[0]; attlist} - SELECT a.attname, a.attnum + columns = Hash[query(<<-SQL, "Columns for index #{row[0]} on #{table_name}")] + SELECT a.attnum, a.attname FROM pg_attribute a WHERE a.attrelid = #{oid} AND a.attnum IN (#{indkey.join(",")}) SQL - column_names = indkey.map {|attnum| columns[attnum] } - IndexDefinition.new(table_name, index_name, unique, column_names) - - end - - indexes + column_names = columns.values_at(*indkey).compact + column_names.empty? ? nil : IndexDefinition.new(table_name, index_name, unique, column_names) + end.compact end # Returns the list of all column definitions for a table. @@ -929,9 +927,8 @@ module ActiveRecord # TIMESTAMP WITH ZONE types in UTC. if ActiveRecord::Base.default_timezone == :utc execute("SET time zone 'UTC'") - else - offset = Time.local(2000).utc_offset / 3600 - execute("SET time zone '#{offset}'") + elsif @local_tz + execute("SET time zone '#{@local_tz}'") end end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index f295af16f0..0d9a86a1ea 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -6,6 +6,10 @@ module ActiveRecord def self.sqlite3_connection(config) # :nodoc: parse_sqlite_config!(config) + unless 'sqlite3' == config[:adapter] + raise ArgumentError, 'adapter name should be "sqlite3"' + end + unless self.class.const_defined?(:SQLite3) require_library_or_gem(config[:adapter]) end @@ -24,13 +28,13 @@ module ActiveRecord module ConnectionAdapters #:nodoc: class SQLite3Adapter < SQLiteAdapter # :nodoc: - + # Returns the current database encoding format as a string, eg: 'UTF-8' def encoding if @connection.respond_to?(:encoding) - @connection.encoding[0]['encoding'] + @connection.encoding.to_s else - encoding = @connection.send(:get_query_pragma, 'encoding') + encoding = @connection.execute('PRAGMA encoding') encoding[0]['encoding'] end end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb index deb62e3802..1927585c49 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite_adapter.rb @@ -151,7 +151,7 @@ module ActiveRecord # DATABASE STATEMENTS ====================================== def execute(sql, name = nil) #:nodoc: - catch_schema_changes { log(sql, name) { @connection.execute(sql) } } + log(sql, name) { @connection.execute(sql) } end def update_sql(sql, name = nil) #:nodoc: @@ -176,15 +176,15 @@ module ActiveRecord end def begin_db_transaction #:nodoc: - catch_schema_changes { @connection.transaction } + @connection.transaction end def commit_db_transaction #:nodoc: - catch_schema_changes { @connection.commit } + @connection.commit end def rollback_db_transaction #:nodoc: - catch_schema_changes { @connection.rollback } + @connection.rollback end # SCHEMA STATEMENTS ======================================== @@ -246,6 +246,7 @@ module ActiveRecord end def remove_column(table_name, *column_names) #:nodoc: + raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty? column_names.flatten.each do |column_name| alter_table(table_name) do |definition| definition.columns.delete(definition[column_name]) @@ -390,17 +391,6 @@ module ActiveRecord end end - def catch_schema_changes - return yield - rescue ActiveRecord::StatementInvalid => exception - if exception.message =~ /database schema has changed/ - reconnect! - retry - else - raise - end - end - def sqlite_version @sqlite_version ||= SQLiteAdapter::Version.new(select_value('select sqlite_version(*)')) end |