提交 a09659d5 编写于 作者: R Rafael Mendonça França

Merge pull request #13313 from ccutrer/temp-tables

support creating temporary tables from queries

Conflicts:
	activerecord/CHANGELOG.md
* Respect temporary option when dropping tables with MySQL.
Normal DROP TABLE also works, but commits the transaction.
*Cody Cutrer*
* Add option to create tables from a query.
*Cody Cutrer*
* `db:test:clone` and `db:test:prepare` must load Rails environment.
`db:test:clone` and `db:test:prepare` use `ActiveRecord::Base`. configurations,
......
......@@ -34,9 +34,10 @@ def visit_ColumnDefinition(o)
def visit_TableDefinition(o)
create_sql = "CREATE#{' TEMPORARY' if o.temporary} TABLE "
create_sql << "#{quote_table_name(o.name)} ("
create_sql << o.columns.map { |c| accept c }.join(', ')
create_sql << ") #{o.options}"
create_sql << "#{quote_table_name(o.name)} "
create_sql << "(#{o.columns.map { |c| accept c }.join(', ')}) " unless o.as
create_sql << "#{o.options}"
create_sql << " AS #{@conn.to_sql(o.as)}" if o.as
create_sql
end
......
......@@ -49,14 +49,15 @@ class TableDefinition
# An array of ColumnDefinition objects, representing the column changes
# that have been defined.
attr_accessor :indexes
attr_reader :name, :temporary, :options
attr_reader :name, :temporary, :options, :as
def initialize(types, name, temporary, options)
def initialize(types, name, temporary, options, as = nil)
@columns_hash = {}
@indexes = {}
@native = types
@temporary = temporary
@options = options
@as = as
@name = name
end
......
......@@ -131,6 +131,9 @@ def column_exists?(table_name, column_name, type = nil, options = {})
# [<tt>:force</tt>]
# Set to true to drop the table before creating it.
# Defaults to false.
# [<tt>:as]
# SQL to use to generate the table. When this option is used, the block is
# ignored, as are the <tt>:id</tt> and <tt>:primary_key</tt> options.
#
# ====== Add a backend specific option to the generated SQL (MySQL)
#
......@@ -169,19 +172,31 @@ def column_exists?(table_name, column_name, type = nil, options = {})
# supplier_id int
# )
#
# ====== Create a temporary table based on a query
#
# create_table(:long_query, temporary: true,
# as: "SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id")
#
# generates:
#
# CREATE TEMPORARY TABLE long_query AS
# SELECT * FROM orders INNER JOIN line_items ON order_id=orders.id
#
# See also TableDefinition#column for details on how to create columns.
def create_table(table_name, options = {})
td = create_table_definition table_name, options[:temporary], options[:options]
td = create_table_definition table_name, options[:temporary], options[:options], options[:as]
unless options[:id] == false
pk = options.fetch(:primary_key) {
Base.get_primary_key table_name.to_s.singularize
}
if !options[:as]
unless options[:id] == false
pk = options.fetch(:primary_key) {
Base.get_primary_key table_name.to_s.singularize
}
td.primary_key pk, options.fetch(:id, :primary_key), options
end
td.primary_key pk, options.fetch(:id, :primary_key), options
end
yield td if block_given?
yield td if block_given?
end
if options[:force] && table_exists?(table_name)
drop_table(table_name, options)
......@@ -826,8 +841,8 @@ def rename_column_indexes(table_name, column_name, new_column_name)
end
private
def create_table_definition(name, temporary, options)
TableDefinition.new native_database_types, name, temporary, options
def create_table_definition(name, temporary, options, as = nil)
TableDefinition.new native_database_types, name, temporary, options, as
end
def create_alter_table(name)
......
......@@ -492,6 +492,10 @@ def rename_table(table_name, new_name)
rename_table_indexes(table_name, new_name)
end
def drop_table(table_name, options = {})
execute "DROP#{' TEMPORARY' if options[:temporary]} TABLE #{quote_table_name(table_name)}"
end
def rename_index(table_name, old_name, new_name)
if (version[0] == 5 && version[1] >= 7) || version[0] >= 6
execute "ALTER TABLE #{quote_table_name(table_name)} RENAME INDEX #{quote_table_name(old_name)} TO #{quote_table_name(new_name)}"
......
......@@ -973,8 +973,8 @@ def extract_table_ref_from_insert_sql(sql)
$1.strip if $1
end
def create_table_definition(name, temporary, options)
TableDefinition.new native_database_types, name, temporary, options
def create_table_definition(name, temporary, options, as = nil)
TableDefinition.new native_database_types, name, temporary, options, as
end
def update_table_definition(table_name, base)
......
......@@ -65,6 +65,15 @@ def test_dump_indexes
assert_nil index_c.using
assert_equal :fulltext, index_c.type
end
def test_drop_temporary_table
@connection.transaction do
@connection.create_table(:temp_table, temporary: true)
# if it doesn't properly say DROP TEMPORARY TABLE, the transaction commit
# will complain that no transaction is active
@connection.drop_table(:temp_table, temporary: true)
end
end
end
end
end
......@@ -443,6 +443,32 @@ def test_create_table_with_binary_column
Person.connection.drop_table :binary_testings rescue nil
end
def test_create_table_with_query
Person.connection.drop_table :table_from_query_testings rescue nil
Person.connection.create_table(:person, force: true)
Person.connection.create_table :table_from_query_testings, as: "SELECT id FROM person"
columns = Person.connection.columns(:table_from_query_testings)
assert_equal 1, columns.length
assert_equal "id", columns.first.name
Person.connection.drop_table :table_from_query_testings rescue nil
end
def test_create_table_with_query_from_relation
Person.connection.drop_table :table_from_query_testings rescue nil
Person.connection.create_table(:person, force: true)
Person.connection.create_table :table_from_query_testings, as: Person.select(:id)
columns = Person.connection.columns(:table_from_query_testings)
assert_equal 1, columns.length
assert_equal "id", columns.first.name
Person.connection.drop_table :table_from_query_testings rescue nil
end
if current_adapter? :OracleAdapter
def test_create_table_with_custom_sequence_name
# table name is 29 chars, the standard sequence name will
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册