From e199dc1a570d4f0d9a07628268835bce5aab2732 Mon Sep 17 00:00:00 2001 From: Dan McClain Date: Mon, 25 Mar 2013 13:33:37 -0400 Subject: Adds support for concurrent indexing in PostgreSQL adapter Adds support for algorithm option in MySQL indexes Moves USING and algorithm options upstream The syntax is still specific to the Adapter, so the actual executed string happens in the corresponding adapter --- .../connection_adapters/abstract/schema_statements.rb | 7 +++++-- .../active_record/connection_adapters/abstract_adapter.rb | 7 +++++++ .../connection_adapters/abstract_mysql_adapter.rb | 12 ++++++------ .../connection_adapters/postgresql/schema_statements.rb | 8 ++------ .../active_record/connection_adapters/postgresql_adapter.rb | 4 ++++ 5 files changed, 24 insertions(+), 14 deletions(-) (limited to 'activerecord/lib/active_record/connection_adapters') 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 26cacbde37..35f1112798 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -752,11 +752,13 @@ module ActiveRecord index_name = index_name(table_name, column: column_names) if Hash === options # legacy support, since this param was a string - options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using) + options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm) index_type = options[:unique] ? "UNIQUE" : "" index_name = options[:name].to_s if options.key?(:name) max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length + algorithm = index_algorithms[options[:algorithm]] + using = "USING #{options[:using]}" if options[:using].present? if supports_partial_index? index_options = options[:where] ? " WHERE #{options[:where]}" : "" @@ -772,6 +774,7 @@ module ActiveRecord index_type = options max_index_length = allowed_index_name_length + algorithm = using = nil end if index_name.length > max_index_length @@ -782,7 +785,7 @@ module ActiveRecord end index_columns = quoted_columns_for_index(column_names, options).join(", ") - [index_name, index_type, index_columns, index_options] + [index_name, index_type, index_columns, index_options, algorithm, using] end def index_name_for_remove(table_name, options = {}) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 0f4ab68b61..1915c444ef 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -282,6 +282,13 @@ module ActiveRecord [] end + # A list of index algorithms, to be filled by adapters that + # support them. MySQL and PostgreSQL has support for them right + # now. + def index_algorithms + {} + end + # QUOTING ================================================== # Returns a bind substitution value given a +column+ and list of current diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb index 71f5c8fd29..ff3e9acfac 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -208,6 +208,10 @@ module ActiveRecord NATIVE_DATABASE_TYPES end + def index_algorithms + { default: 'ALGORITHM = DEFAULT', copy: 'ALGORITHM = COPY', inplace: 'ALGORITHM = INPLACE' } + end + # HELPER METHODS =========================================== # The two drivers have slightly different ways of yielding hashes of results, so @@ -506,12 +510,8 @@ module ActiveRecord end def add_index(table_name, column_name, options = {}) #:nodoc: - if options.is_a?(Hash) && options[:using] - index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options) - execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} USING #{options[:using]} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options}" - else - super - end + index_name, index_type, index_columns, index_options, index_algorithm, index_using = add_index_options(table_name, column_name, options) + execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} #{index_using} ON #{quote_table_name(table_name)} (#{index_columns})#{index_options} #{index_algorithm}" end # Maps logical Rails types to MySQL-specific data types. diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb index 688bf1774b..0e1afbae8d 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -410,12 +410,8 @@ module ActiveRecord end def add_index(table_name, column_name, options = {}) #:nodoc: - if options.is_a?(Hash) && options[:using] - index_name, index_type, index_columns, index_options = add_index_options(table_name, column_name, options) - execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} USING #{options[:using]} (#{index_columns})#{index_options}" - else - super - end + index_name, index_type, index_columns, index_options, index_algorithm, index_using = add_index_options(table_name, column_name, options) + execute "CREATE #{index_type} INDEX #{index_algorithm} #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{index_using} (#{index_columns})#{index_options}" end def remove_index!(table_name, index_name) #:nodoc: diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index d26b676335..46e41e6b48 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -433,6 +433,10 @@ module ActiveRecord true end + def index_algorithms + { concurrently: 'CONCURRENTLY' } + end + class StatementPool < ConnectionAdapters::StatementPool def initialize(connection, max) super -- cgit v1.2.3 From 203e0e0e4a863a25fedfe6985b371c3f4cfc6839 Mon Sep 17 00:00:00 2001 From: Dan McClain Date: Mon, 25 Mar 2013 22:41:29 -0400 Subject: Checks :algorithm argument for valid values --- .../connection_adapters/abstract/schema_statements.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record/connection_adapters') 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 35f1112798..d5ae4058ed 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -757,7 +757,13 @@ module ActiveRecord index_type = options[:unique] ? "UNIQUE" : "" index_name = options[:name].to_s if options.key?(:name) max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length - algorithm = index_algorithms[options[:algorithm]] + + if index_algorithms.key?(options[:algorithm]) + algorithm = index_algorithms[options[:algorithm]] + elsif options[:algorithm].present? + raise ArgumentError.new("Algorithm must be one of the following: #{index_algorithms.keys.map(&:inspect).join(', ')}") + end + using = "USING #{options[:using]}" if options[:using].present? if supports_partial_index? -- cgit v1.2.3