From a6fefad354d36f3e9a91f8582659ffcda1a35855 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 1 Jan 2005 18:55:04 +0000 Subject: Added the final touches to the Microsoft SQL Server adapter by DeLynn Berry that makes it suitable for actual use #394 [DeLynn Barry] git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@302 5ecf4fe2-1ee6-0310-87b1-e25e094e27de --- activerecord/CHANGELOG | 2 + activerecord/Rakefile | 6 +++ .../connection_adapters/sqlserver_adapter.rb | 49 ++++++++++++++++++---- .../connections/native_sqlserver/connection.rb | 12 ++++-- 4 files changed, 57 insertions(+), 12 deletions(-) diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 855ea9cfbc..eb21ad9be0 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Added the final touches to the Microsoft SQL Server adapter by DeLynn Berry that makes it suitable for actual use #394 [DeLynn Barry] + * Fixed a bug in the Ruby/MySQL that caused binary content to be escaped badly and come back mangled #405 [Tobias Luetke] * Added block-style for callbacks #332 [bitsweat]. diff --git a/activerecord/Rakefile b/activerecord/Rakefile index 9352a4b6b8..30db268556 100755 --- a/activerecord/Rakefile +++ b/activerecord/Rakefile @@ -45,6 +45,12 @@ Rake::TestTask.new("test_sqlite") { |t| t.verbose = true } +Rake::TestTask.new("test_sqlserver") { |t| + t.libs << "test" << "test/connections/native_sqlserver" + t.pattern = 'test/*_test.rb' + t.verbose = true +} + # Generate the RDoc documentation Rake::RDocTask.new { |rdoc| diff --git a/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb index 5c48dc377d..d01085c395 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlserver_adapter.rb @@ -33,13 +33,17 @@ module ActiveRecord symbolize_strings_in_hash(config) - if config.has_key? :dsn - dsn = config[:dsn] + host = config[:host] + username = config[:username] ? config[:username].to_s : 'sa' + password = config[:password].to_s + + if config.has_key? :database + database = config[:database] else - raise ArgumentError, "No DSN specified" + raise ArgumentError, "No database specified. Missing argument: database." end - conn = DBI.connect(dsn) + conn = DBI.connect("DBI:ADO:Provider=SQLOLEDB;Data Source=#{host};Initial Catalog=#{database};User Id=#{username};Password=#{password};") conn["AutoCommit"] = true ConnectionAdapters::SQLServerAdapter.new(conn, logger) @@ -59,7 +63,7 @@ module ActiveRecord class SQLServerAdapter < AbstractAdapter # :nodoc: def quote_column_name(name) - " [#{name}] " + "[#{name}]" end def select_all(sql, name = nil) @@ -82,7 +86,6 @@ JOIN sysobjects AS s ON (c.id = s.id) LEFT OUTER JOIN syscomments AS com ON (c.cdefault = com.id) WHERE s.name = '#{table_name}' EOL - columns = [] log(sql, name, @connection) do |conn| @@ -151,8 +154,12 @@ EOL end end - alias_method :update, :execute - alias_method :delete, :execute + def update(sql, name = nil) + execute(sql, name) + affected_rows(name) + end + + alias_method :delete, :update def begin_db_transaction begin @@ -192,7 +199,13 @@ EOL end def add_limit!(sql, limit) - sql.gsub!(/SELECT/i, "SELECT TOP #{limit}") + limit_amount = limit.to_s.include?("OFFSET") ? get_offset_amount(limit) : Array.new([limit]) + order_by = sql.include?("ORDER BY") ? get_order_by(sql.sub(/.*ORDER\sBY./, "")) : nil + if limit_amount.size == 2 + sql.gsub!(/SELECT/i, "SELECT * FROM ( SELECT TOP #{limit_amount[0]} * FROM ( SELECT TOP #{limit_amount[1]}")<<" ) AS tmp1 ORDER BY #{order_by[1]} ) AS tmp2 ORDER BY #{order_by[0]}" + else + sql.gsub!(/SELECT/i, "SELECT TOP #{limit_amount[0]}") + end end private @@ -252,6 +265,24 @@ EOL def query_contains_identity_column(sql, col) return sql =~ /[\(\.\,]\s*#{col}/ end + + def get_order_by(sql) + return sql, sql.gsub(/\s*DESC\s*/, "").gsub(/\s*ASC\s*/, " DESC") + end + + def get_offset_amount(limit) + limit = limit.gsub!(/.OFFSET./i, ",").split(',') + return limit[0].to_i, limit[0].to_i+limit[1].to_i + end + + def affected_rows(name = nil) + sql = "SELECT @@ROWCOUNT AS AffectedRows" + log(sql, name, @connection) do |conn| + conn.select_all(sql) do |row| + return row[:AffectedRows].to_i + end + end + end end end end \ No newline at end of file diff --git a/activerecord/test/connections/native_sqlserver/connection.rb b/activerecord/test/connections/native_sqlserver/connection.rb index b198f21c4b..8d758a02ab 100644 --- a/activerecord/test/connections/native_sqlserver/connection.rb +++ b/activerecord/test/connections/native_sqlserver/connection.rb @@ -6,10 +6,16 @@ ActiveRecord::Base.logger = Logger.new("debug.log") ActiveRecord::Base.establish_connection( :adapter => "sqlserver", - :dsn => "DBI:ADO:Provider=SQLOLEDB;Data Source=(local);Initial Catalog=test;User Id=sa;Password=password;" + :host => "localhost", + :username => "sa", + :password => "", + :database => db1 ) Course.establish_connection( - :adapter => "sqlserver", - :dsn => "DBI:ADO:Provider=SQLOLEDB;Data Source=(local);Initial Catalog=test2;User Id=sa;Password=password;" + :adapter => "sqlserver", + :host => "localhost", + :username => "sa", + :password => "", + :database => db2 ) -- cgit v1.2.3