Skip to content

Commit

Permalink
Fixed SQL Server adapter so it honors options[:conditions] when apply…
Browse files Browse the repository at this point in the history
…ing :limits (closes #1978) [Tom Ward] Fixed SQL Server adapter to pass even more tests and do even better (closes #2634) [rtomayko@gmail.com]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@2781 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information
dhh committed Oct 28, 2005
1 parent 9bafd35 commit e508595
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 15 deletions.
4 changes: 4 additions & 0 deletions activerecord/CHANGELOG
@@ -1,5 +1,9 @@
*SVN*

* Fixed SQL Server adapter to pass even more tests and do even better #2634 [rtomayko@gmail.com]

* Fixed SQL Server adapter so it honors options[:conditions] when applying :limits #1978 [Tom Ward]

* Added migration support to SQL Server adapter (please someone do the same for Oracle and DB2) #2625 [Tom Ward]

* Use AR::Base.silence rather than AR::Base.logger.silence in fixtures to preserve Log4r compatibility. #2618 [dansketcher@gmail.com]
Expand Down
Expand Up @@ -222,7 +222,7 @@ def initialize_schema_information
def dump_schema_information #:nodoc:
begin
if (current_schema = ActiveRecord::Migrator.current_version) > 0
return "INSERT INTO #{ActiveRecord::Migrator.schema_info_table_name} (version) VALUES (#{current_schema});"
return "INSERT INTO #{ActiveRecord::Migrator.schema_info_table_name} (version) VALUES (#{current_schema})"
end
rescue ActiveRecord::StatementInvalid
# No Schema Info
Expand Down
Expand Up @@ -77,6 +77,7 @@ def type_cast(value)
when :datetime then cast_to_datetime(value)
when :timestamp then cast_to_time(value)
when :time then cast_to_time(value)
when :date then cast_to_datetime(value)
when :boolean then value == true or (value =~ /^t(rue)?$/i) == 0 or value.to_s == '1'
else value
end
Expand Down Expand Up @@ -198,7 +199,7 @@ def select_all(sql, name = nil)
end

def select_one(sql, name = nil)
add_limit!(sql, nil)
add_limit!(sql, :limit => 1)
result = select(sql, name)
result.nil? ? nil : result.first
end
Expand Down Expand Up @@ -317,15 +318,27 @@ def quote_column_name(name)
end

def add_limit_offset!(sql, options)
if options.has_key?(:limit) and options.has_key?(:offset) and !options[:limit].nil? and !options[:offset].nil?
options[:order] ||= "id ASC"
total_rows = @connection.select_all("SELECT count(*) as TotalRows from #{get_table_name(sql)}")[0][:TotalRows].to_i
if (options[:limit] + options[:offset]) > total_rows
options[:limit] = (total_rows - options[:offset] > 0) ? (total_rows - options[:offset]) : 1
if options[:limit] and options[:offset]
total_rows = @connection.select_all("SELECT count(*) as TotalRows from (#{sql.gsub(/SELECT/i, "SELECT TOP 1000000000")}) tally")[0][:TotalRows].to_i
if (options[:limit] + options[:offset]) >= total_rows
options[:limit] = (total_rows - options[:offset] >= 0) ? (total_rows - options[:offset]) : 0
end
sql.gsub!(/SELECT/i, "SELECT * FROM ( SELECT TOP #{options[:limit]} * FROM ( SELECT TOP #{options[:limit] + options[:offset]}")<<" ) AS tmp1 ORDER BY #{change_order_direction(options[:order])} ) AS tmp2 ORDER BY #{options[:order]}"
else
sql.gsub!(/SELECT/i, "SELECT TOP #{options[:limit]}") unless options[:limit].nil?
sql.sub!(/^\s*SELECT/i, "SELECT * FROM (SELECT TOP #{options[:limit]} * FROM (SELECT TOP #{options[:limit] + options[:offset]} ")
sql << ") AS tmp1"
if options[:order]
options[:order] = options[:order].split(',').map do |field|
parts = field.split(" ")
if sql =~ /#{parts[0]} AS (t\d_r\d\d?)/
parts[0] = $1
end
parts.join(' ')
end.join(', ')
sql << " ORDER BY #{change_order_direction(options[:order])}) AS tmp2 ORDER BY #{options[:order]}"
else
sql << " ) AS tmp2"
end
elsif sql !~ /^\s*SELECT (@@|COUNT\()/i
sql.sub!(/^\s*SELECT/i, "SELECT TOP #{options[:limit]}") unless options[:limit].nil?
end
end

Expand Down Expand Up @@ -423,9 +436,9 @@ def enable_identity_insert(table_name, enable = true)
end

def get_table_name(sql)
if sql =~ /into\s*([^\s]+)\s*|update\s*([^\s]+)\s*/i
if sql =~ /into\s*([^\(\s]+)\s*|update\s*([^\(\s]+)\s*/i
$1
elsif sql =~ /from\s*([^\s]+)\s*/i
elsif sql =~ /from\s*([^\(\s]+)\s*/i
$1
else
nil
Expand Down Expand Up @@ -460,8 +473,8 @@ def change_order_direction(order)

def get_special_columns(table_name)
special = []
@table_columns = {} unless @table_columns
@table_columns[table_name] = columns(table_name) if @table_columns[table_name] == nil
@table_columns ||= {}
@table_columns[table_name] ||= columns(table_name)
@table_columns[table_name].each do |col|
special << col.name if col.is_special
end
Expand All @@ -472,6 +485,7 @@ def repair_special_columns(sql)
special_cols = get_special_columns(get_table_name(sql))
for col in special_cols.to_a
sql.gsub!(Regexp.new(" #{col.to_s} = "), " #{col.to_s} LIKE ")
sql.gsub!(/ORDER BY #{col.to_s}/i, '')
end
sql
end
Expand Down
6 changes: 6 additions & 0 deletions activerecord/test/finder_test.rb
Expand Up @@ -56,6 +56,12 @@ def test_find_all_with_prepared_limit_and_offset
assert_equal(1, entrants.size)
assert_equal(entrants(:third).name, entrants.first.name)
end

def test_find_with_limit_and_condition
developers = Developer.find(:all, :order => "id DESC", :conditions => "salary = 100000", :limit => 3, :offset =>7)
assert_equal(1, developers.size)
assert_equal("fixture_3", developers.first.name)
end

def test_find_with_entire_select_statement
topics = Topic.find_by_sql "SELECT * FROM topics WHERE author_name = 'Mary'"
Expand Down
Expand Up @@ -22,6 +22,6 @@ DROP TABLE authors;
DROP TABLE tasks;
DROP TABLE categories;
DROP TABLE categories_posts;
DROP TABLE fk_test_has_pd;
DROP TABLE fk_test_has_fk;
DROP TABLE fk_test_has_pk;
DROP TABLE keyboards;

0 comments on commit e508595

Please sign in to comment.