diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index fa230df993..477bc1b54a 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,4 +1,4 @@ -* SQLite3 adapter supports expression indexes +* SQLite3 adapter supports expression indexes. ``` create_table :users do |t| diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb index 0e254455b6..46ca7e07a9 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3/schema_statements.rb @@ -21,23 +21,24 @@ module ActiveRecord WHERE name = #{quote(row['name'])} AND type = 'index' SQL - /\sON\s+"(\w+?)"\s+\((?.+?)\)(\sWHERE\s+(?.+))?$/i =~ index_sql + /\bON\b\s*"?(\w+?)"?\s*\((?.+?)\)(?:\s*WHERE\b\s*(?.+))?\z/i =~ index_sql columns = exec_query("PRAGMA index_info(#{quote(row['name'])})", "SCHEMA").map do |col| col["name"] end - if columns.any?(&:nil?) # index created with an expression - columns = expressions.split(", ").map { |e| e.gsub(/^\"|\"?$/, "") } - end - - # Add info on sort order for columns (only desc order is explicitly specified, asc is - # the default) orders = {} - if index_sql # index_sql can be null in case of primary key indexes - index_sql.scan(/"(\w+)" DESC/).flatten.each { |order_column| - orders[order_column] = :desc - } + + if columns.any?(&:nil?) # index created with an expression + columns = expressions + else + # Add info on sort order for columns (only desc order is explicitly specified, + # asc is the default) + if index_sql # index_sql can be null in case of primary key indexes + index_sql.scan(/"(\w+)" DESC/).flatten.each { |order_column| + orders[order_column] = :desc + } + end end IndexDefinition.new( diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 51f4944808..d32fd5ea09 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -487,9 +487,12 @@ module ActiveRecord name = name[1..-1] end - to_column_names = columns(to).map(&:name) - columns = index.columns.map { |c| rename[c] || c }.select do |column| - to_column_names.include?(column) + columns = index.columns + if columns.is_a?(Array) + to_column_names = columns(to).map(&:name) + columns = columns.map { |c| rename[c] || c }.select do |column| + to_column_names.include?(column) + end end unless columns.empty? diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index 320f6efd56..7b73621ed9 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -348,34 +348,35 @@ module ActiveRecord if ActiveRecord::Base.connection.supports_expression_index? def test_expression_index with_example_table do - @conn.add_index "ex", "abs(number)", name: "expression" + @conn.add_index "ex", "max(id, number)", name: "expression" index = @conn.indexes("ex").find { |idx| idx.name == "expression" } - assert_equal %w{ abs(number) }, index.columns + assert_equal "max(id, number)", index.columns end end def test_expression_index_with_where with_example_table do - @conn.add_index "ex", "id % 10, abs(number)", name: "expression", where: "id > 1000" + @conn.add_index "ex", "id % 10, max(id, number)", name: "expression", where: "id > 1000" index = @conn.indexes("ex").find { |idx| idx.name == "expression" } - assert_equal ["id % 10", "abs(number)"], index.columns + assert_equal "id % 10, max(id, number)", index.columns assert_equal "id > 1000", index.where end end def test_complicated_expression with_example_table do - @conn.add_index "ex", "id % 10, (CASE WHEN number > 0 THEN abs(number) END)", name: "expression" + @conn.execute "CREATE INDEX expression ON ex (id % 10, (CASE WHEN number > 0 THEN max(id, number) END))WHERE(id > 1000)" index = @conn.indexes("ex").find { |idx| idx.name == "expression" } - assert_equal ["id % 10", "(CASE WHEN number > 0 THEN abs(number) END)"], index.columns + assert_equal "id % 10, (CASE WHEN number > 0 THEN max(id, number) END)", index.columns + assert_equal "(id > 1000)", index.where end end def test_not_everything_an_expression with_example_table do - @conn.add_index "ex", %w{ id abs(number) }, name: "expression" + @conn.add_index "ex", "id, max(id, number)", name: "expression" index = @conn.indexes("ex").find { |idx| idx.name == "expression" } - assert_equal %w{ id abs(number) }.sort, index.columns.sort + assert_equal "id, max(id, number)", index.columns end end end