Skip to content

Commit

Permalink
Merge remote branch 'rsim/oracle_enhanced_rails3'
Browse files Browse the repository at this point in the history
  • Loading branch information
wycats committed Jun 8, 2010
2 parents 0042f41 + acef8fe commit b97a3f3
Show file tree
Hide file tree
Showing 14 changed files with 54 additions and 47 deletions.
3 changes: 2 additions & 1 deletion activerecord/lib/active_record/associations.rb
Expand Up @@ -1756,7 +1756,8 @@ def join_base
end end


def count_aliases_from_table_joins(name) def count_aliases_from_table_joins(name)
quoted_name = join_base.active_record.connection.quote_table_name(name.downcase) # quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase
quoted_name = join_base.active_record.connection.quote_table_name(name.downcase).downcase
join_sql = join_base.table_joins.to_s.downcase join_sql = join_base.table_joins.to_s.downcase
join_sql.blank? ? 0 : join_sql.blank? ? 0 :
# Table names # Table names
Expand Down
7 changes: 5 additions & 2 deletions activerecord/lib/active_record/relation.rb
Expand Up @@ -356,13 +356,16 @@ def with_create_scope
end end


def references_eager_loaded_tables? def references_eager_loaded_tables?
joined_tables = (tables_in_string(arel.joins(arel)) + [table.name, table.table_alias]).compact.uniq # always convert table names to downcase as in Oracle quoted table names are in uppercase
joined_tables = (tables_in_string(arel.joins(arel)) + [table.name, table.table_alias]).compact.map(&:downcase).uniq
(tables_in_string(to_sql) - joined_tables).any? (tables_in_string(to_sql) - joined_tables).any?
end end


def tables_in_string(string) def tables_in_string(string)
return [] if string.blank? return [] if string.blank?
string.scan(/([a-zA-Z_][\.\w]+).?\./).flatten.uniq # always convert table names to downcase as in Oracle quoted table names are in uppercase
# ignore raw_sql_ that is used by Oracle adapter as alias for limit/offset subqueries
string.scan(/([a-zA-Z_][\.\w]+).?\./).flatten.map(&:downcase).uniq - ['raw_sql_']
end end


end end
Expand Down
17 changes: 4 additions & 13 deletions activerecord/test/cases/adapter_test.rb
Expand Up @@ -145,22 +145,13 @@ def test_foreign_key_violations_are_translated_to_specific_exception


def test_add_limit_offset_should_sanitize_sql_injection_for_limit_without_comas def test_add_limit_offset_should_sanitize_sql_injection_for_limit_without_comas
sql_inject = "1 select * from schema" sql_inject = "1 select * from schema"
assert_equal " LIMIT 1", @connection.add_limit_offset!("", :limit => sql_inject) assert_no_match /schema/, @connection.add_limit_offset!("", :limit=>sql_inject)
if current_adapter?(:MysqlAdapter) assert_no_match /schema/, @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7)
assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit => sql_inject, :offset => 7)
else
assert_equal " LIMIT 1 OFFSET 7", @connection.add_limit_offset!("", :limit => sql_inject, :offset => 7)
end
end end


def test_add_limit_offset_should_sanitize_sql_injection_for_limit_with_comas def test_add_limit_offset_should_sanitize_sql_injection_for_limit_with_comas
sql_inject = "1, 7 procedure help()" sql_inject = "1, 7 procedure help()"
if current_adapter?(:MysqlAdapter) assert_no_match /procedure/, @connection.add_limit_offset!("", :limit=>sql_inject)
assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit => sql_inject) assert_no_match /procedure/, @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7)
assert_equal " LIMIT 7, 1", @connection.add_limit_offset!("", :limit => '1 ; DROP TABLE USERS', :offset => 7)
else
assert_equal " LIMIT 1,7", @connection.add_limit_offset!("", :limit => sql_inject)
assert_equal " LIMIT 1,7 OFFSET 7", @connection.add_limit_offset!("", :limit => sql_inject, :offset => 7)
end
end end
end end
Expand Up @@ -37,6 +37,10 @@ def test_belongs_to_with_primary_key_joins_on_correct_column
if current_adapter?(:MysqlAdapter) if current_adapter?(:MysqlAdapter)
assert_no_match(/`firm_with_primary_keys_companies`\.`id`/, sql) assert_no_match(/`firm_with_primary_keys_companies`\.`id`/, sql)
assert_match(/`firm_with_primary_keys_companies`\.`name`/, sql) assert_match(/`firm_with_primary_keys_companies`\.`name`/, sql)
elsif current_adapter?(:OracleAdapter)
# on Oracle aliases are truncated to 30 characters and are quoted in uppercase
assert_no_match(/"firm_with_primary_keys_compani"\."id"/i, sql)
assert_match(/"firm_with_primary_keys_compani"\."name"/i, sql)
else else
assert_no_match(/"firm_with_primary_keys_companies"\."id"/, sql) assert_no_match(/"firm_with_primary_keys_companies"\."id"/, sql)
assert_match(/"firm_with_primary_keys_companies"\."name"/, sql) assert_match(/"firm_with_primary_keys_companies"\."name"/, sql)
Expand Down
Expand Up @@ -511,7 +511,7 @@ def test_deleting_before_save
end end


def test_deleting_updates_counter_cache def test_deleting_updates_counter_cache
topic = Topic.first topic = Topic.first(:order => "id ASC")
assert_equal topic.replies.to_a.size, topic.replies_count assert_equal topic.replies.to_a.size, topic.replies_count


topic.replies.delete(topic.replies.first) topic.replies.delete(topic.replies.first)
Expand Down
7 changes: 4 additions & 3 deletions activerecord/test/cases/base_test.rb
Expand Up @@ -430,14 +430,14 @@ def test_non_attribute_access_and_assignment
end end


def test_preserving_date_objects def test_preserving_date_objects
if current_adapter?(:SybaseAdapter, :OracleAdapter) if current_adapter?(:SybaseAdapter)
# Sybase ctlib does not (yet?) support the date type; use datetime instead. # Sybase ctlib does not (yet?) support the date type; use datetime instead.
# Oracle treats all dates/times as Time.
assert_kind_of( assert_kind_of(
Time, Topic.find(1).last_read, Time, Topic.find(1).last_read,
"The last_read attribute should be of the Time class" "The last_read attribute should be of the Time class"
) )
else else
# Oracle enhanced adapter allows to define Date attributes in model class (see topic.rb)
assert_kind_of( assert_kind_of(
Date, Topic.find(1).last_read, Date, Topic.find(1).last_read,
"The last_read attribute should be of the Date class" "The last_read attribute should be of the Date class"
Expand Down Expand Up @@ -2125,10 +2125,11 @@ def test_to_xml
assert_equal "integer", xml.elements["//parent-id"].attributes['type'] assert_equal "integer", xml.elements["//parent-id"].attributes['type']
assert_equal "true", xml.elements["//parent-id"].attributes['nil'] assert_equal "true", xml.elements["//parent-id"].attributes['nil']


if current_adapter?(:SybaseAdapter, :OracleAdapter) if current_adapter?(:SybaseAdapter)
assert_equal last_read_in_current_timezone, xml.elements["//last-read"].text assert_equal last_read_in_current_timezone, xml.elements["//last-read"].text
assert_equal "datetime" , xml.elements["//last-read"].attributes['type'] assert_equal "datetime" , xml.elements["//last-read"].attributes['type']
else else
# Oracle enhanced adapter allows to define Date attributes in model class (see topic.rb)
assert_equal "2004-04-15", xml.elements["//last-read"].text assert_equal "2004-04-15", xml.elements["//last-read"].text
assert_equal "date" , xml.elements["//last-read"].attributes['type'] assert_equal "date" , xml.elements["//last-read"].attributes['type']
end end
Expand Down
4 changes: 3 additions & 1 deletion activerecord/test/cases/date_time_test.rb
Expand Up @@ -5,7 +5,9 @@
class DateTimeTest < ActiveRecord::TestCase class DateTimeTest < ActiveRecord::TestCase
def test_saves_both_date_and_time def test_saves_both_date_and_time
time_values = [1807, 2, 10, 15, 30, 45] time_values = [1807, 2, 10, 15, 30, 45]
now = DateTime.civil(*time_values) # create DateTime value with local time zone offset
local_offset = Rational(Time.local_time(*time_values).utc_offset, 86400)
now = DateTime.civil(*(time_values + [local_offset]))


task = Task.new task = Task.new
task.starting = now task.starting = now
Expand Down
4 changes: 2 additions & 2 deletions activerecord/test/cases/log_subscriber_test.rb
Expand Up @@ -27,7 +27,7 @@ def test_basic_query_logging
wait wait
assert_equal 1, @logger.logged(:debug).size assert_equal 1, @logger.logged(:debug).size
assert_match(/Developer Load/, @logger.logged(:debug).last) assert_match(/Developer Load/, @logger.logged(:debug).last)
assert_match(/SELECT .*?FROM .?developers.?/, @logger.logged(:debug).last) assert_match(/SELECT .*?FROM .?developers.?/i, @logger.logged(:debug).last)
end end


def test_cached_queries def test_cached_queries
Expand All @@ -38,6 +38,6 @@ def test_cached_queries
wait wait
assert_equal 2, @logger.logged(:debug).size assert_equal 2, @logger.logged(:debug).size
assert_match(/CACHE/, @logger.logged(:debug).last) assert_match(/CACHE/, @logger.logged(:debug).last)
assert_match(/SELECT .*?FROM .?developers.?/, @logger.logged(:debug).last) assert_match(/SELECT .*?FROM .?developers.?/i, @logger.logged(:debug).last)
end end
end end
33 changes: 16 additions & 17 deletions activerecord/test/cases/migration_test.rb
Expand Up @@ -30,13 +30,14 @@ def test_add_schema_info_respects_prefix_and_suffix
conn = ActiveRecord::Base.connection conn = ActiveRecord::Base.connection


conn.drop_table(ActiveRecord::Migrator.schema_migrations_table_name) if conn.table_exists?(ActiveRecord::Migrator.schema_migrations_table_name) conn.drop_table(ActiveRecord::Migrator.schema_migrations_table_name) if conn.table_exists?(ActiveRecord::Migrator.schema_migrations_table_name)
ActiveRecord::Base.table_name_prefix = 'foo_' # Use shorter prefix and suffix as in Oracle database identifier cannot be larger than 30 characters
ActiveRecord::Base.table_name_suffix = '_bar' ActiveRecord::Base.table_name_prefix = 'p_'
ActiveRecord::Base.table_name_suffix = '_s'
conn.drop_table(ActiveRecord::Migrator.schema_migrations_table_name) if conn.table_exists?(ActiveRecord::Migrator.schema_migrations_table_name) conn.drop_table(ActiveRecord::Migrator.schema_migrations_table_name) if conn.table_exists?(ActiveRecord::Migrator.schema_migrations_table_name)


conn.initialize_schema_migrations_table conn.initialize_schema_migrations_table


assert_equal "foo_unique_schema_migrations_bar", conn.indexes(ActiveRecord::Migrator.schema_migrations_table_name)[0][:name] assert_equal "p_unique_schema_migrations_s", conn.indexes(ActiveRecord::Migrator.schema_migrations_table_name)[0][:name]
ensure ensure
ActiveRecord::Base.table_name_prefix = "" ActiveRecord::Base.table_name_prefix = ""
ActiveRecord::Base.table_name_suffix = "" ActiveRecord::Base.table_name_suffix = ""
Expand Down Expand Up @@ -83,13 +84,17 @@ def test_add_index


# Orcl nds shrt indx nms. Sybs 2. # Orcl nds shrt indx nms. Sybs 2.
# OpenBase does not have named indexes. You must specify a single column name # OpenBase does not have named indexes. You must specify a single column name
unless current_adapter?(:OracleAdapter, :SybaseAdapter, :OpenBaseAdapter) unless current_adapter?(:SybaseAdapter, :OpenBaseAdapter)
assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) } assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
assert_nothing_raised { Person.connection.remove_index("people", :column => ["last_name", "first_name"]) } assert_nothing_raised { Person.connection.remove_index("people", :column => ["last_name", "first_name"]) }
assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) } # Oracle adapter cannot have specified index name larger than 30 characters
assert_nothing_raised { Person.connection.remove_index("people", :name => "index_people_on_last_name_and_first_name") } # Oracle adapter is shortening index name when just column list is given
assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) } unless current_adapter?(:OracleAdapter)
assert_nothing_raised { Person.connection.remove_index("people", "last_name_and_first_name") } assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
assert_nothing_raised { Person.connection.remove_index("people", :name => "index_people_on_last_name_and_first_name") }
assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
assert_nothing_raised { Person.connection.remove_index("people", "last_name_and_first_name") }
end
assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) } assert_nothing_raised { Person.connection.add_index("people", ["last_name", "first_name"]) }
assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) } assert_nothing_raised { Person.connection.remove_index("people", ["last_name", "first_name"]) }
assert_nothing_raised { Person.connection.add_index("people", ["last_name"], :length => 10) } assert_nothing_raised { Person.connection.add_index("people", ["last_name"], :length => 10) }
Expand Down Expand Up @@ -736,13 +741,7 @@ def test_remove_column_with_multi_column_index
table.column :hat_size, :integer table.column :hat_size, :integer
table.column :hat_style, :string, :limit => 100 table.column :hat_style, :string, :limit => 100
end end
# Oracle index names should be 30 or less characters ActiveRecord::Base.connection.add_index "hats", ["hat_style", "hat_size"], :unique => true
if current_adapter?(:OracleAdapter)
ActiveRecord::Base.connection.add_index "hats", ["hat_style", "hat_size"], :unique => true,
:name => 'index_hats_on_hat_style_size'
else
ActiveRecord::Base.connection.add_index "hats", ["hat_style", "hat_size"], :unique => true
end


assert_nothing_raised { Person.connection.remove_column("hats", "hat_size") } assert_nothing_raised { Person.connection.remove_column("hats", "hat_size") }
ensure ensure
Expand Down Expand Up @@ -1375,8 +1374,8 @@ def test_create_table_with_custom_sequence_name
return unless current_adapter? :OracleAdapter return unless current_adapter? :OracleAdapter


# table name is 29 chars, the standard sequence name will # table name is 29 chars, the standard sequence name will
# be 33 chars and fail # be 33 chars and should be shortened
assert_raise(ActiveRecord::StatementInvalid) do assert_nothing_raised do
begin begin
Person.connection.create_table :table_with_name_thats_just_ok do |t| Person.connection.create_table :table_with_name_thats_just_ok do |t|
t.column :foo, :string, :null => false t.column :foo, :string, :null => false
Expand Down
2 changes: 1 addition & 1 deletion activerecord/test/connections/native_oracle/connection.rb
Expand Up @@ -53,7 +53,7 @@


# for assert_queries test helper # for assert_queries test helper
ActiveRecord::Base.connection.class.class_eval do ActiveRecord::Base.connection.class.class_eval do
IGNORED_SELECT_SQL = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /^\s*select .* from all_tab_columns/im] IGNORED_SELECT_SQL = [/^select .*nextval/i, /^SAVEPOINT/, /^ROLLBACK TO/, /^\s*select .* from ((all|user)_tab_columns|(all|user)_triggers|(all|user)_constraints)/im]


def select_with_query_record(sql, name = nil, return_column_names = false) def select_with_query_record(sql, name = nil, return_column_names = false)
$queries_executed ||= [] $queries_executed ||= []
Expand Down
6 changes: 6 additions & 0 deletions activerecord/test/models/topic.rb
Expand Up @@ -43,6 +43,12 @@ def extension_two
before_create :default_written_on before_create :default_written_on
before_destroy :destroy_children before_destroy :destroy_children


# Explicitly define as :date column so that returned Oracle DATE values would be typecasted to Date and not Time.
# Some tests depend on assumption that this attribute will have Date values.
if current_adapter?(:OracleEnhancedAdapter)
set_date_columns :last_read
end

def parent def parent
Topic.find(parent_id) Topic.find(parent_id)
end end
Expand Down
Expand Up @@ -60,7 +60,7 @@ def readable_inspect
# Converts self to a Ruby Date object; time portion is discarded # Converts self to a Ruby Date object; time portion is discarded
def to_date def to_date
::Date.new(year, month, day) ::Date.new(year, month, day)
end unless method_defined?(:to_date) end unless instance_methods(false).include?(:to_date)


# Attempts to convert self to a Ruby Time object; returns self if out of range of Ruby Time class # Attempts to convert self to a Ruby Time object; returns self if out of range of Ruby Time class
# If self has an offset other than 0, self will just be returned unaltered, since there's no clean way to map it to a Time # If self has an offset other than 0, self will just be returned unaltered, since there's no clean way to map it to a Time
Expand All @@ -71,7 +71,7 @@ def to_time
# To be able to keep Times, Dates and DateTimes interchangeable on conversions # To be able to keep Times, Dates and DateTimes interchangeable on conversions
def to_datetime def to_datetime
self self
end unless method_defined?(:to_datetime) end unless instance_methods(false).include?(:to_datetime)


def self.civil_from_format(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0) def self.civil_from_format(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0)
offset = utc_or_local.to_sym == :local ? local_offset : 0 offset = utc_or_local.to_sym == :local ? local_offset : 0
Expand All @@ -81,7 +81,7 @@ def self.civil_from_format(utc_or_local, year, month=1, day=1, hour=0, min=0, se
# Converts datetime to an appropriate format for use in XML # Converts datetime to an appropriate format for use in XML
def xmlschema def xmlschema
strftime("%Y-%m-%dT%H:%M:%S%Z") strftime("%Y-%m-%dT%H:%M:%S%Z")
end unless method_defined?(:xmlschema) end unless instance_methods(false).include?(:xmlschema)


# Converts self to a floating-point number of seconds since the Unix epoch # Converts self to a floating-point number of seconds since the Unix epoch
def to_f def to_f
Expand Down
2 changes: 1 addition & 1 deletion activesupport/test/abstract_unit.rb
Expand Up @@ -18,7 +18,7 @@
require 'active_support' require 'active_support'


# Include shims until we get off 1.8.6 # Include shims until we get off 1.8.6
require 'active_support/ruby/shim' require 'active_support/ruby/shim' if RUBY_VERSION < '1.8.7'


def uses_memcached(test_name) def uses_memcached(test_name)
require 'memcache' require 'memcache'
Expand Down
4 changes: 2 additions & 2 deletions activesupport/test/core_ext/date_time_ext_test.rb
Expand Up @@ -26,11 +26,11 @@ def test_custom_date_format
end end


def test_to_date def test_to_date
assert_equal Date.new(2005, 2, 21), DateTime.new(2005, 2, 21).to_date assert_equal Date.new(2005, 2, 21), DateTime.new(2005, 2, 21, 14, 30, 0).to_date
end end


def test_to_datetime def test_to_datetime
assert_equal DateTime.new(2005, 2, 21), DateTime.new(2005, 2, 21).to_datetime assert_equal DateTime.new(2005, 2, 21, 14, 30, 0), DateTime.new(2005, 2, 21, 14, 30, 0).to_datetime
end end


def test_to_time def test_to_time
Expand Down

0 comments on commit b97a3f3

Please sign in to comment.