diff options
Diffstat (limited to 'activerecord/lib')
12 files changed, 85 insertions, 40 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 40175c8c8c..285b4065b1 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb @@ -23,6 +23,20 @@ module ActiveRecord table_name[0...table_alias_length].tr('.', '_') end + # Returns the relation names useable to back Active Record models. + # For most adapters this means all #tables and #views. + def data_sources + tables | views + end + + # Checks to see if the data source +name+ exists on the database. + # + # data_source_exists?(:ebooks) + # + def data_source_exists?(name) + data_sources.include?(name.to_s) + end + # Returns an array of table names defined in the database. def tables(name = nil) raise NotImplementedError, "#tables is not implemented" 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 feb41e96f0..79a24d1996 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -628,6 +628,7 @@ module ActiveRecord def tables(name = nil) # :nodoc: select_values("SHOW FULL TABLES", 'SCHEMA') end + alias data_sources tables def truncate(table_name, name = nil) execute "TRUNCATE TABLE #{quote_table_name(table_name)}", name @@ -644,6 +645,7 @@ module ActiveRecord select_values(sql, 'SCHEMA').any? end + alias data_source_exists? table_exists? def views # :nodoc: select_values("SHOW FULL TABLES WHERE table_type = 'VIEW'", 'SCHEMA') 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 66d311dd48..aaf5b2898b 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb @@ -73,6 +73,16 @@ module ActiveRecord select_values("SELECT tablename FROM pg_tables WHERE schemaname = ANY(current_schemas(false))", 'SCHEMA') end + def data_sources # :nodoc + select_values(<<-SQL, 'SCHEMA') + SELECT c.relname + FROM pg_class c + LEFT JOIN pg_namespace n ON n.oid = c.relnamespace + WHERE c.relkind IN ('r', 'v','m') -- (r)elation/table, (v)iew, (m)aterialized view + AND n.nspname = ANY (current_schemas(false)) + SQL + end + # Returns true if table exists. # If the schema is not specified as part of +name+ then it will only find tables within # the current schema search path (regardless of permissions to access tables in other schemas) @@ -89,6 +99,7 @@ module ActiveRecord AND n.nspname = #{name.schema ? "'#{name.schema}'" : 'ANY (current_schemas(false))'} SQL end + alias data_source_exists? table_exists? def views # :nodoc: select_values(<<-SQL, 'SCHEMA') diff --git a/activerecord/lib/active_record/connection_adapters/schema_cache.rb b/activerecord/lib/active_record/connection_adapters/schema_cache.rb index 981d5d7a3c..eee142378c 100644 --- a/activerecord/lib/active_record/connection_adapters/schema_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/schema_cache.rb @@ -10,7 +10,7 @@ module ActiveRecord @columns = {} @columns_hash = {} @primary_keys = {} - @tables = {} + @data_sources = {} end def initialize_dup(other) @@ -18,33 +18,38 @@ module ActiveRecord @columns = @columns.dup @columns_hash = @columns_hash.dup @primary_keys = @primary_keys.dup - @tables = @tables.dup + @data_sources = @data_sources.dup end def primary_keys(table_name) - @primary_keys[table_name] ||= table_exists?(table_name) ? connection.primary_key(table_name) : nil + @primary_keys[table_name] ||= data_source_exists?(table_name) ? connection.primary_key(table_name) : nil end # A cached lookup for table existence. - def table_exists?(name) - prepare_tables if @tables.empty? - return @tables[name] if @tables.key? name + def data_source_exists?(name) + prepare_data_sources if @data_sources.empty? + return @data_sources[name] if @data_sources.key? name - @tables[name] = connection.table_exists?(name) + @data_sources[name] = connection.data_source_exists?(name) end + alias table_exists? data_source_exists? + deprecate :table_exists? => "use #data_source_exists? instead" + # Add internal cache for table with +table_name+. def add(table_name) - if table_exists?(table_name) + if data_source_exists?(table_name) primary_keys(table_name) columns(table_name) columns_hash(table_name) end end - def tables(name) - @tables[name] + def data_sources(name) + @data_sources[name] end + alias tables data_sources + deprecate :tables => "use #data_sources instead" # Get the columns for a table def columns(table_name) @@ -64,36 +69,38 @@ module ActiveRecord @columns.clear @columns_hash.clear @primary_keys.clear - @tables.clear + @data_sources.clear @version = nil end def size - [@columns, @columns_hash, @primary_keys, @tables].map(&:size).inject :+ + [@columns, @columns_hash, @primary_keys, @data_sources].map(&:size).inject :+ end - # Clear out internal caches for table with +table_name+. - def clear_table_cache!(table_name) - @columns.delete table_name - @columns_hash.delete table_name - @primary_keys.delete table_name - @tables.delete table_name + # Clear out internal caches for the data source +name+. + def clear_data_source_cache!(name) + @columns.delete name + @columns_hash.delete name + @primary_keys.delete name + @data_sources.delete name end + alias clear_table_cache! clear_data_source_cache! + deprecate :clear_table_cache! => "use #clear_data_source_cache! instead" def marshal_dump # if we get current version during initialization, it happens stack over flow. @version = ActiveRecord::Migrator.current_version - [@version, @columns, @columns_hash, @primary_keys, @tables] + [@version, @columns, @columns_hash, @primary_keys, @data_sources] end def marshal_load(array) - @version, @columns, @columns_hash, @primary_keys, @tables = array + @version, @columns, @columns_hash, @primary_keys, @data_sources = array end private - def prepare_tables - connection.tables.each { |table| @tables[table] = true } + def prepare_data_sources + connection.data_sources.each { |source| @data_sources[source] = true } end end end diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index e2f52707e8..f6a6e3eb4d 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -319,10 +319,12 @@ module ActiveRecord row['name'] end end + alias data_sources tables def table_exists?(table_name) table_name && tables(nil, table_name).any? end + alias data_source_exists? table_exists? def views # :nodoc: select_values("SELECT name FROM sqlite_master WHERE type = 'view' AND name <> 'sqlite_sequence'", 'SCHEMA') diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb index 2b0c755ef4..c461c04a26 100644 --- a/activerecord/lib/active_record/model_schema.rb +++ b/activerecord/lib/active_record/model_schema.rb @@ -213,7 +213,7 @@ module ActiveRecord # Indicates whether the table associated with this class exists def table_exists? - connection.schema_cache.table_exists?(table_name) + connection.schema_cache.data_source_exists?(table_name) end def attributes_builder # :nodoc: @@ -290,7 +290,7 @@ module ActiveRecord def reset_column_information connection.clear_cache! undefine_attribute_methods - connection.schema_cache.clear_table_cache!(table_name) + connection.schema_cache.clear_data_source_cache!(table_name) reload_schema_from_cache end diff --git a/activerecord/lib/active_record/railties/databases.rake b/activerecord/lib/active_record/railties/databases.rake index d543a84ff1..b113baec33 100644 --- a/activerecord/lib/active_record/railties/databases.rake +++ b/activerecord/lib/active_record/railties/databases.rake @@ -255,7 +255,7 @@ db_namespace = namespace :db do filename = File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, "schema_cache.dump") con.schema_cache.clear! - con.tables.each { |table| con.schema_cache.add(table) } + con.data_sources.each { |table| con.schema_cache.add(table) } open(filename, 'wb') { |f| f.write(Marshal.dump(con.schema_cache)) } end diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index 0f6015fa93..c562bd9ce4 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -70,9 +70,9 @@ module ActiveRecord # +calculate+ for examples with options. # # Person.sum(:age) # => 4562 - def sum(*args) - return super if block_given? - calculate(:sum, *args) + def sum(column_name = nil, &block) + return super(&block) if block_given? + calculate(:sum, column_name) end # This calculates aggregate values in the given column. Methods for count, sum, average, diff --git a/activerecord/lib/active_record/sanitization.rb b/activerecord/lib/active_record/sanitization.rb index ba75ffa5a1..32f4229977 100644 --- a/activerecord/lib/active_record/sanitization.rb +++ b/activerecord/lib/active_record/sanitization.rb @@ -15,7 +15,7 @@ module ActiveRecord # them into a valid SQL fragment for a WHERE clause. # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'" # "name='foo''bar' and group_id='4'" returns "name='foo''bar' and group_id='4'" - def sanitize_sql_for_conditions(condition, table_name = self.table_name) + def sanitize_sql_for_conditions(condition) return nil if condition.blank? case condition diff --git a/activerecord/lib/active_record/schema_dumper.rb b/activerecord/lib/active_record/schema_dumper.rb index f1f827f163..2362dae9fc 100644 --- a/activerecord/lib/active_record/schema_dumper.rb +++ b/activerecord/lib/active_record/schema_dumper.rb @@ -89,7 +89,7 @@ HEADER end def tables(stream) - sorted_tables = @connection.tables.sort - @connection.views + sorted_tables = @connection.data_sources.sort - @connection.views sorted_tables.each do |table_name| table(table_name, stream) unless ignored?(table_name) diff --git a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb index ba5dd0a0d9..8929aa85c8 100644 --- a/activerecord/lib/active_record/tasks/mysql_database_tasks.rb +++ b/activerecord/lib/active_record/tasks/mysql_database_tasks.rb @@ -56,22 +56,21 @@ module ActiveRecord end def structure_dump(filename) - args = prepare_command_options('mysqldump') + args = prepare_command_options args.concat(["--result-file", "#{filename}"]) args.concat(["--no-data"]) args.concat(["--routines"]) args.concat(["#{configuration['database']}"]) - unless Kernel.system(*args) - $stderr.puts "Could not dump the database structure. "\ - "Make sure `mysqldump` is in your PATH and check the command output for warnings." - end + + run_cmd('mysqldump', args, 'dumping') end def structure_load(filename) - args = prepare_command_options('mysql') + args = prepare_command_options args.concat(['--execute', %{SET FOREIGN_KEY_CHECKS = 0; SOURCE #{filename}; SET FOREIGN_KEY_CHECKS = 1}]) args.concat(["--database", "#{configuration['database']}"]) - Kernel.system(*args) + + run_cmd('mysql', args, 'loading') end private @@ -130,7 +129,7 @@ IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION; $stdin.gets.strip end - def prepare_command_options(command) + def prepare_command_options args = { 'host' => '--host', 'port' => '--port', @@ -145,7 +144,17 @@ IDENTIFIED BY '#{configuration['password']}' WITH GRANT OPTION; 'sslkey' => '--ssl-key' }.map { |opt, arg| "#{arg}=#{configuration[opt]}" if configuration[opt] }.compact - [command, *args] + args + end + + def run_cmd(cmd, args, action) + fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args) + end + + def run_cmd_error(cmd, args, action) + msg = "failed to execute: `#{cmd}`\n" + msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n" + msg end end end diff --git a/activerecord/lib/active_record/type_caster/connection.rb b/activerecord/lib/active_record/type_caster/connection.rb index 3878270770..868d08ed44 100644 --- a/activerecord/lib/active_record/type_caster/connection.rb +++ b/activerecord/lib/active_record/type_caster/connection.rb @@ -20,7 +20,7 @@ module ActiveRecord private def column_for(attribute_name) - if connection.schema_cache.table_exists?(table_name) + if connection.schema_cache.data_source_exists?(table_name) connection.schema_cache.columns_hash(table_name)[attribute_name.to_s] end end |