Browse files

Support returning the number of rows updated/deleted on MSSQL when us…

…ing the ADO adapter with an explicit :provider

I'd like to be able to do this for ADO in general, but it appears as
though ADO uses pass by reference with an integer to set the number
of rows affected by the query, which isn't supported by ruby.  As I
don't know how to work around this, I instead added some code to
the MSSQL ADO subadapter to use a second query to get the number of
rows modified.  However, since I believe this requires the same
connection to be used, it's only enabled when an explicit :provider
is given, since the default provider uses a new connection for
each query.  Reduces the test suite unhandled failures from 24 to 8
when using the SQLNCLI10 provider.
  • Loading branch information...
1 parent cd04eb9 commit 43d91cf1a123721a65b1c509fa6093af28ade145 @jeremyevans committed Apr 30, 2010
Showing with 35 additions and 1 deletion.
  1. +2 −0 CHANGELOG
  2. +33 −1 lib/sequel/adapters/ado/mssql.rb
View
2 CHANGELOG
@@ -1,5 +1,7 @@
=== HEAD
+* Support returning the number of rows updated/deleted on MSSQL when using the ADO adapter with an explicit :provider (jeremyevans)
+
* Support transactions in the ADO adapter if not using the default :provider (jeremyevans)
* Make Database#disconnect not raise an exception when using the unsharded single connection pool (jeremyevans)
View
34 lib/sequel/adapters/ado/mssql.rb
@@ -7,23 +7,55 @@ module ADO
module MSSQL
module DatabaseMethods
include Sequel::MSSQL::DatabaseMethods
+ # Query to use to get the number of rows affected by an update or
+ # delete query.
+ ROWS_AFFECTED = "SELECT @@ROWCOUNT AS AffectedRows"
# Return instance of Sequel::ADO::MSSQL::Dataset with the given opts.
def dataset(opts=nil)
Sequel::ADO::MSSQL::Dataset.new(self, opts)
end
+
+ # Just execute so it doesn't attempt to return the number of rows modified.
+ def execute_ddl(sql, opts={})
+ execute(sql, opts)
+ end
+ alias execute_insert execute_ddl
+
+ # Issue a separate query to get the rows modified. ADO appears to
+ # use pass by reference with an integer variable, which is obviously
+ # not supported directly in ruby, and I'm not aware of a workaround.
+ def execute_dui(sql, opts={})
+ return super unless @opts[:provider]
+ synchronize(opts[:server]) do |conn|
+ begin
+ log_yield(sql){conn.Execute(sql)}
+ res = log_yield(ROWS_AFFECTED){conn.Execute(ROWS_AFFECTED)}
+ res.getRows.transpose.each{|r| return r.shift}
+ rescue ::WIN32OLERuntimeError => e
+ raise_error(e)
+ end
+ end
+ end
end
class Dataset < ADO::Dataset
include Sequel::MSSQL::DatasetMethods
# Use a nasty hack of multiple SQL statements in the same call and
# having the last one return the most recently inserted id. This
- # is necessary as ADO doesn't provide a consistent native connection.
+ # is necessary as ADO's default :provider uses a separate native
+ # connection for each query.
def insert(*values)
return super if @opts[:sql]
with_sql("SET NOCOUNT ON; #{insert_sql(*values)}; SELECT CAST(SCOPE_IDENTITY() AS INTEGER)").single_value
end
+
+ # If you use a better :provider option for the database, you can get an
+ # accurate number of rows matched.
+ def provides_accurate_rows_matched?
+ !!db.opts[:provider]
+ end
end
end
end

0 comments on commit 43d91cf

Please sign in to comment.