diff options
author | Ryuta Kamizono <kamipo@gmail.com> | 2016-02-01 00:23:36 +0900 |
---|---|---|
committer | Jeremy Daer <jeremydaer@gmail.com> | 2016-04-24 14:56:29 -0700 |
commit | edc2b7718725016e988089b5fb6d6fb9d6e16882 (patch) | |
tree | 2dc5eb1b68ff7c0f71c5de73578e48cb5edb6d68 /activerecord/lib/active_record | |
parent | c41ef01aec40bfaa9af707551d1e8a1f9f7380d1 (diff) | |
download | rails-edc2b7718725016e988089b5fb6d6fb9d6e16882.tar.gz rails-edc2b7718725016e988089b5fb6d6fb9d6e16882.tar.bz2 rails-edc2b7718725016e988089b5fb6d6fb9d6e16882.zip |
Add Expression Indexes and Operator Classes support for PostgreSQL
Example:
create_table :users do |t|
t.string :name
t.index 'lower(name) varchar_pattern_ops'
end
Fixes #19090.
Fixes #21765.
Fixes #21819.
Fixes #24359.
Signed-off-by: Jeremy Daer <jeremydaer@gmail.com>
Diffstat (limited to 'activerecord/lib/active_record')
4 files changed, 46 insertions, 18 deletions
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 f65dc4ed5a..99a3e99bdc 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -1110,15 +1110,19 @@ module ActiveRecord Table.new(table_name, base) end - def add_index_options(table_name, column_name, comment: nil, **options) #:nodoc: - column_names = Array(column_name) + def add_index_options(table_name, column_name, comment: nil, **options) # :nodoc: + if column_name.is_a?(String) && /\W/ === column_name + column_names = column_name + else + column_names = Array(column_name) + end options.assert_valid_keys(:unique, :order, :name, :where, :length, :internal, :using, :algorithm, :type) index_type = options[:type].to_s if options.key?(:type) index_type ||= options[:unique] ? "UNIQUE" : "" index_name = options[:name].to_s if options.key?(:name) - index_name ||= index_name(table_name, column: column_names) + index_name ||= index_name(table_name, index_name_options(column_names)) max_index_length = options.fetch(:internal, false) ? index_name_length : allowed_index_name_length if options.key?(:algorithm) @@ -1174,6 +1178,8 @@ module ActiveRecord # Overridden by the MySQL adapter for supporting index lengths def quoted_columns_for_index(column_names, options = {}) + return [column_names] if column_names.is_a?(String) + option_strings = Hash[column_names.map {|name| [name, '']}] # add index sort order if supported @@ -1249,6 +1255,14 @@ module ActiveRecord AlterTable.new create_table_definition(name) end + def index_name_options(column_names) # :nodoc: + if column_names.is_a?(String) + column_names = column_names.scan(/\w+/).join('_') + end + + { column: column_names } + end + def foreign_key_name(table_name, options) # :nodoc: identifier = "#{table_name}_#{options.fetch(:column)}_fk" hashed_identifier = Digest::SHA256.hexdigest(identifier).first(10) diff --git a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb index 130c03dd1d..86de8f1ca0 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb @@ -248,6 +248,11 @@ module ActiveRecord false end + # Does this adapter support expression indices? + def supports_expression_index? + false + end + # Does this adapter support explain? def supports_explain? false 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 272e6293ab..074ebb90a5 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -175,7 +175,10 @@ module ActiveRecord result = query(<<-SQL, 'SCHEMA') SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid, - pg_catalog.obj_description(i.oid, 'pg_class') AS comment + pg_catalog.obj_description(i.oid, 'pg_class') AS comment, + (SELECT COUNT(*) FROM pg_opclass o + JOIN (SELECT unnest(string_to_array(d.indclass::text, ' '))::int oid) c + ON o.oid = c.oid WHERE o.opcdefault = 'f') FROM pg_class t INNER JOIN pg_index d ON t.oid = d.indrelid INNER JOIN pg_class i ON d.indexrelid = i.oid @@ -194,25 +197,27 @@ module ActiveRecord inddef = row[3] oid = row[4] comment = row[5] + opclass = row[6] - columns = Hash[query(<<-SQL, "SCHEMA")] - SELECT a.attnum, a.attname - FROM pg_attribute a - WHERE a.attrelid = #{oid} - AND a.attnum IN (#{indkey.join(",")}) - SQL + using, expressions, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: WHERE (.+))?\z/).flatten - column_names = columns.values_at(*indkey).compact + if indkey.include?(0) || opclass > 0 + columns = expressions + else + columns = Hash[query(<<-SQL.strip_heredoc, "SCHEMA")].values_at(*indkey).compact + SELECT a.attnum, a.attname + FROM pg_attribute a + WHERE a.attrelid = #{oid} + AND a.attnum IN (#{indkey.join(",")}) + SQL - unless column_names.empty? # add info on sort order for columns (only desc order is explicitly specified, asc is the default) - desc_order_columns = inddef.scan(/(\w+) DESC/).flatten - orders = desc_order_columns.any? ? Hash[desc_order_columns.map {|order_column| [order_column, :desc]}] : {} - where = inddef.scan(/WHERE (.+)$/).flatten[0] - using = inddef.scan(/USING (.+?) /).flatten[0].to_sym - - IndexDefinition.new(table_name, index_name, unique, column_names, [], orders, where, nil, using, comment) + orders = Hash[ + expressions.scan(/(\w+) DESC/).flatten.map { |order_column| [order_column, :desc] } + ] end + + IndexDefinition.new(table_name, index_name, unique, columns, [], orders, where, nil, using.to_sym, comment) end.compact end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index e397a28cac..39a2cbbda7 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -140,6 +140,10 @@ module ActiveRecord true end + def supports_expression_index? + true + end + def supports_transaction_isolation? true end |