Created
July 26, 2010 16:45
-
-
Save thinkerbot/490817 to your computer and use it in GitHub Desktop.
tables_in_string patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'test/unit' | |
# These tests illustrate that the tables_in_string will not properly handle | |
# oracle table names containing valid non-word characters like '$' or those | |
# suffixed with a db link. As a consequence, eager loading can revert to the | |
# left-outer-join strategy and ignore select statements on find (see | |
# http://gist.github.com/486750). | |
# | |
# To fix the issue, the regexp in tables_in_string needs to be updated to | |
# handle fully-qualified oracle names. As you can see it's kinda ugly to do | |
# so, and obviously the oraclisms only apply to oracle. I propose | |
# tables_in_string gets moved onto the adapter. | |
# | |
# To run this test: | |
# | |
# % ruby tables_in_string_test.rb # tests current, fails | |
# % PATCH=true ruby tables_in_string_test.rb # tests patch, passes | |
# | |
# == Example | |
# | |
# Works: | |
# | |
# class Dept < ActiveRecord::Base | |
# set_table_name 'dept' | |
# end | |
# | |
# class Emp < ActiveRecord::Base | |
# set_table_name 'emp' | |
# belongs_to :dept, :select => 'id, name nombre' | |
# end | |
# | |
# puts Emp.find(1, :include => :dept).dept.nombre | |
# | |
# Doesn't work: | |
# | |
# class Dept < ActiveRecord::Base | |
# set_table_name "schema$name.dept" | |
# end | |
# | |
# class Emp < ActiveRecord::Base | |
# set_table_name "schema$name.emp" | |
# belongs_to :dept, :select => "id, name nombre" | |
# end | |
# | |
# Emp.find(1, :include => :dept).dept.nombre # !> NoMethodError | |
# | |
class TablesInStringTest < Test::Unit::TestCase | |
NONQUOTED_OBJECT_NAME = /[A-Za-z][A-z0-9$#]{0,29}/ | |
NONQUOTED_DATABASE_LINK = /[A-Za-z][A-z0-9$#\.@]{0,127}/ | |
# Pick which regexp to use based on the PATCH ENV variable | |
TABLES_IN_STRING = ENV['PATCH'] == 'true' ? | |
/((?:#{NONQUOTED_OBJECT_NAME}\.)?#{NONQUOTED_OBJECT_NAME}(?:@#{NONQUOTED_DATABASE_LINK})?)\..?/ : | |
/([a-zA-Z_][\.\w]+).?\./ | |
# The original code in 3.0 -- see active_record/relation.rb | |
# | |
# class String | |
# def blank? | |
# self !~ /\S/ | |
# end | |
# end | |
# | |
# def tables_in_string(string) | |
# return [] if string.blank? | |
# # 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 | |
# | |
def tables_in_string(string) | |
return [] if string !~ /\S/ | |
string.scan(TABLES_IN_STRING).flatten.map {|str| str.downcase }.uniq - ['raw_sql_'] | |
end | |
# | |
# tables_in_string test | |
# | |
def test_tables_in_string | |
assert_equal %w{one two three}, tables_in_string('one.a, two.b, three.c') | |
end | |
def test_tables_in_fully_qualified_string | |
assert_equal %w{ | |
tablename | |
schemaname.tablename | |
schemaname.tablename@dblink | |
}, tables_in_string('tablename.a, schemaname.tablename.b, schemaname.tablename@dblink.c') | |
end | |
def test_tables_in_string_with_acceptable_non_word_characters | |
assert_equal %w{ | |
abc$#_123.abc$#_123@abc$#@._123 | |
}, tables_in_string('abc$#_123.abc$#_123@abc$#@._123.columnone, abc$#_123.abc$#_123@abc$#@._123.columntwo') | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment