Skip to content

Commit 63c94ef

Browse files
stevericeSteve Rice
authored andcommitted
Fixes bugs for using indexes in CREATE TABLE by adding checks for table existence
Also: - updates tests by stubbing table_exists? method - adds entry for creating indexes in CREATE TABLE to changelog
1 parent afa148a commit 63c94ef

File tree

5 files changed

+25
-6
lines changed

5 files changed

+25
-6
lines changed

activerecord/CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
* Create indexes inline in CREATE TABLE for MySQL
2+
3+
This is important, because adding an index on a temporary table after it has been created
4+
would commit the transaction.
5+
It also allows creating and dropping indexed tables with fewer queries and fewer permissions required.
6+
7+
Example:
8+
9+
create_table :temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query" do |t|
10+
t.index :zip
11+
end
12+
# => CREATE TEMPORARY TABLE temp (INDEX (zip)) AS SELECT id, name, zip FROM a_really_complicated_query
13+
14+
*Cody Cutrer*, *Steve Rice*
15+
116
* Save `has_one` association even if the record doesn't changed.
217

318
Fixes #14407.

activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,7 @@ def add_index_options(table_name, column_name, options = {})
795795
if index_name.length > max_index_length
796796
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' is too long; the limit is #{max_index_length} characters"
797797
end
798-
if index_name_exists?(table_name, index_name, false)
798+
if table_exists?(table_name) && index_name_exists?(table_name, index_name, false)
799799
raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' already exists"
800800
end
801801
index_columns = quoted_columns_for_index(column_names, options).join(", ")

activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ def visit_TableDefinition(o)
1212
statements = []
1313
statements.concat(o.columns.map { |c| accept c })
1414
statements.concat(o.indexes.map { |(column_name, options)| index_in_create(o.name, column_name, options) })
15-
create_sql << "(#{statements.join(', ')}) "
15+
create_sql << "(#{statements.join(', ')}) " if statements.present?
1616
create_sql << "#{o.options}"
1717
create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
1818
create_sql

activerecord/test/cases/adapters/mysql/active_schema_test.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ def execute(sql, name = nil) return sql end
1717
end
1818

1919
def test_add_index
20-
# add_index calls index_name_exists? which can't work since execute is stubbed
20+
# add_index calls table_exists? and index_name_exists? which can't work since execute is stubbed
21+
def (ActiveRecord::Base.connection).table_exists?(*); true; end
2122
def (ActiveRecord::Base.connection).index_name_exists?(*); false; end
2223

2324
expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`) "
@@ -118,7 +119,8 @@ def test_remove_timestamps
118119

119120
def test_indexes_in_create
120121
begin
121-
ActiveRecord::Base.connection.stubs(:index_name_exists?).returns(false)
122+
ActiveRecord::Base.connection.stubs(:table_exists?).with(:temp).returns(false)
123+
ActiveRecord::Base.connection.stubs(:index_name_exists?).with(:index_temp_on_zip).returns(false)
122124
expected = "CREATE TEMPORARY TABLE `temp` (INDEX `index_temp_on_zip` (`zip`)) ENGINE=InnoDB AS SELECT id, name, zip FROM a_really_complicated_query"
123125
actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t|
124126
t.index :zip

activerecord/test/cases/adapters/mysql2/active_schema_test.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ def execute(sql, name = nil) return sql end
1717
end
1818

1919
def test_add_index
20-
# add_index calls index_name_exists? which can't work since execute is stubbed
20+
# add_index calls table_exists? and index_name_exists? which can't work since execute is stubbed
21+
def (ActiveRecord::Base.connection).table_exists?(*); true; end
2122
def (ActiveRecord::Base.connection).index_name_exists?(*); false; end
2223

2324
expected = "CREATE INDEX `index_people_on_last_name` ON `people` (`last_name`) "
@@ -118,7 +119,8 @@ def test_remove_timestamps
118119

119120
def test_indexes_in_create
120121
begin
121-
ActiveRecord::Base.connection.stubs(:index_name_exists?).returns(false)
122+
ActiveRecord::Base.connection.stubs(:table_exists?).with(:temp).returns(false)
123+
ActiveRecord::Base.connection.stubs(:index_name_exists?).with(:index_temp_on_zip).returns(false)
122124
expected = "CREATE TEMPORARY TABLE `temp` (INDEX `index_temp_on_zip` (`zip`)) ENGINE=InnoDB AS SELECT id, name, zip FROM a_really_complicated_query"
123125
actual = ActiveRecord::Base.connection.create_table(:temp, temporary: true, as: "SELECT id, name, zip FROM a_really_complicated_query") do |t|
124126
t.index :zip

0 commit comments

Comments
 (0)